Episode: 1292 Title: HPR1292: Doomsday Remainders Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr1292/hpr1292.mp3 Transcribed: 2025-10-17 23:05:15 --- Hello, and welcome to Hacker Public Radio. This is Charles from New Jersey, and I'm back with yet another episode on Recreational Map. But before I start this episode, we have a public service announcement from the Fake Ken Fallon. Hello, everyone. This is the Fake Ken Fallon for Hacker Public Radio. If you've got a pastime, a hobby, or a project that's interesting enough that you find yourself spending time on it, or going on about it with your mates over a beer, you should consider recording a few minutes of audio for Hacker Public Radio. Don't worry about adding a bunch of detailed show notes like Charles and L.J., or producing the perfect recording. Just tell us what you're doing so we can learn about it. You can record your piece using your music player, your computer, or your phone, and send it to the admin, or you could just phone it in to our call-in lines. The main thing is that we want to hear from you on Hacker Public Radio, your ideas and projects podcasted. Well, thanks, Fake Ken. I'm sure that everyone listening will be eager to record their own show. Hello, and welcome to Hacker Public Radio. This is Charles and L.J., and I'm back with another episode on Recreational Now. This is actually another one of those follow-up episodes, and I'm calling today's show, Doomsday Remainters. At the end of episode 1240 on the Doomsday Rule, I mentioned the mod function, which I used in the sample spreadsheets and resource files for that show. Now the name mod is short for modulus, which is just a fancy word for the divisor used to look at remainders in integer division. In terms also used in other contexts, so if you want to do a keyword search, you should probably add remainder or integer to the word modulus to get better results. Now the mod function and integer division go beyond spreadsheets. Most programming language also have a mod function, or an operator that looks like 8% B or A mod B, where mod is the actual word mod MOD in lowercase letters, because it's useful in programming. Now you may only use it for simple things like odd even parity checks, but there are a number of different things you can do in a programming concept with the mod function. As it turns out, and as I discovered as I rushed those files together, there are differences in the behavior of mod operators and functions in different environments, so you have to pay attention, which unfortunately I did not, but I did have a chance to fix them before they went out. Now it may be confusing that a function that comes from mathematics would work differently in different places. You might think that a math function would have a single unchanging definition, but that's not really true here. Now I'm going to explain a couple of the conventions that are used, and show that they're not completely arbitrary, and that you can have a difference of opinion on this particular function. When I talk about using a mod operator that finds the remainder you get from dividing say 77 by 3, I'm going to use the shorthand form 77 MOD 3. That's going to be quicker and less cumbersome, I'm going to mention it a number of times. But before we go on to these differences in implementation, let's talk about the basics of integer division for a minute or so. Now integer division is a little different from the floating point math you have on your calculators and in your spreadsheets. There are similarities, of course. Both of them have a dividend, call it x, a divisor, d, and some kind of quotient. For instance, we can compute 24 divided by 3 either way, and the quotient is the same in either case. In any case where you have integers as inputs and you can afford to just lock off any fraction of bits after the decimal point, integer and floating point division will produce values that are close enough for you for the quotient. But floating point and integer division are not the same. For one thing, integer division on computers is exact, whereas floating point division even with answers that look like integers is always approximate. The two operations are conceptually distinct, so we're not just talking about little differences in how they're computed. Strictly speaking, integer division always gives two answers, the quotient and the remainder. The first example where we divided 24 by 3 was intended to highlight the common elements between floating point and integer math. The next example is going to emphasize the major difference, namely the remainder. Now when I divide 77 by 3 using integer division, I would normally say that the quotient is 25 would a remainder 2 because 25 times 3 or 75 and 26 times 3 or 78 come as close as possible to 77. Now 78 is actually closer to the target, so we could have gone the other way, but for the moment we'll prefer positive remainders. Now I've selected the number 25 as the quotient by convention to get the kind of remainder that I want. Now I normally like a remainder that's both non-negative and as small as possible, but there are other perfectly consistent ways to define it that still work and that I'll describe later on. So integer division always has these two answers. If the dividend x can be written as an integer quotient, call it q, times the divisor d, we say that d divides x because x is equal to q times d. Now indeed defines x, you might be tempted to say there's no remainder, but for both programming and mathematical purposes, it's probably more convenient to say that we have a remainder but it's equal to zero. Now there's no law that says we have to track both the quotient and the remainder in every problem, but both of them are always present by definition, they're always there. In fact this is such an important property of integer arithmetic that the programming languages Python and Ruby have a built-in function div mod that return both the quotient and the remainder as an ordered pair. So for example if I call 77 div mod 3, my return value would be 25 comma 2, it's an ordered pair, where 25 is the quotient and 2 is the remainder. Well technically that would be div mod 77 comma 3, but I can define an operator that does the same thing. Now what would prompt us to make use of either the quotient or the remainder but not both? Well the Doomsday rule that we talked about last time makes use of integer division products in three different ways on the way to finding its answer. Now Conway's Doomsday algorithm for finding the day of the week for a given date has a few steps and each one uses a kind of integer divide. First we use target year div mod 100 to split the target year into its century and an offset year. The century number is used to get the baseline day of the week and the century offset is that set of leftover years that go to the next step as the input. So for example if the target year is 1944, century number is 19 and the offset year is 44. Now going back a step, if you listen to episode 1240 you'll recall that the baseline day is found by adding the results of 36,524 mod 7 for each century since the last 400 year cycle began. Now to understand with that magic number came from you're going to have to listen to the episode. Okay now given the century offset year we can break the problem down further by using century offset div mod 12 to get the pair of numbers that represent first the completed cycles which add plus one to the offset for each one and then the cycle offset which also adds plus one for each year into the incomplete cycle and then we do an additional check on the cycle offset in a next step. Now that next step is we need to adjust the count the total offset for the number of leap years in the current incomplete 12 year cycle which is a quotient only division of the cycle offset which is left over years by four years per leap year and we can call that cycle offset div 4 where div is the integer divide that keeps only the quotient and throws everything else out. As you can recall the div would be the first element in the return value for div mod so div mod and div and mod for the individual operators it's a consistent way of referring to these things and people in some context do call them do call these operators by those names. Now the last part is a little messy and I refer you to the show to follow the process to the end but it's all based on x mod 7 for quite a few different little values of x. So here we have in one calculation we see three different uses of integer division. One we have the 12 year cycle and century adjustment that used both the quotient and remainder. We've got the leap year count that uses just the quotient because there are no partial leap years and then for the final day of the week and a few other places the remainder is the answer so we use remainder only math or the mod function. Now I hadn't planned it this way at the start of this series emerging series but we keep pulling layers off the mathematics onion as we're going along here. Remember the first show had calendar counting which led to counting objects and then we went to doomsday then doomsday led to a discussion of mod div and div mod and to some of the foundations of grade school arithmetic and how and why we use it the way we do. Now in this show I'm going to look mostly at mod because it's the least familiar of the integer division use cases. I think we've seen the others many times before. I know we can skip the quotient only case because you can do that with a calculator and just chop off everything after the decimal. Actually even tracking quotient remainder pairs is not that new to us because we have done this before. Now every time we've used split unit measures those are just quotient remainder pairs. So we don't think twice about referring to a marathon courses being 26 miles 385 yards or giving the running time for a 1500 meter raise as 4 minutes 22 seconds. Now we also use div mod more or less successfully to know when we should start roasting let's say an 11 kilo turkey that needs to cook for 33 minutes per kilogram and then we have to allow for a 90 minute cool down after cooking before we can carve and serve it. Now if you botched that calculation you could have a house full of angry in laws waiting for their dinner and probably most of them did not necessarily need a reason to dislike you so this is a calculation you should learn to get right. I told you this was going to be useful for life. As for the less familiar remainder only form of integer division or the mod function but we've seen that it's good for finding dates on the calendar dates of the week it's also good for finding times of day on the clock. Now we do this whenever we try to interpret Ken's countdown clock for the next HPR community news which he usually starts up several days in advance with more than 100 hours to go. Given our attendance record lately maybe we need to do an episode on figuring out what time of day does the community news is held but that's another topic for another time. Now there are other applications of the mod function that don't involve times or dates and I guess we can touch on those a little later. For now let's go back to the scripts and the spreadsheets from the Doomsday show so I can explain a little bit more about how they work. Now in the spreadsheets and the Python scripts and the functions for BC the mod operations carried a lot of the freight in making the Doomsday rule algorithm work on your computer. A few minutes ago I casually mentioned that we choose the properties of our remainders to follow our preferred conventions and that we happen to like our remainders positive. Now that word convention was carefully chosen. There are other ways to define our remainder that are perfectly valid and self consistent. The main differences in practice are in the sign of the remainder for expressions with say negative input values. Some implementations follow the sign of the divisor so say x mod minus 7 is always negative and otherwise we're okay. Now there are other systems that follow the sign of the number being divided, the dividend, or they set the quotient to make the remainder as small as possible. The third list of the sign plus or minus. Now just for good measure there are some mod operators that just always give a positive result. And there's an argument you could make for each approach and each one of these should generally work as long as you know what the assumptions are. I guess the most important thing is to know the assumptions for the version of the mod function or operator that you're going to use. Now if you've done much programming you know that you'll eventually want to use someone else's code or some cool libraries to do part of a job or maybe all of a job. Now you're going to face the same issues in using their calling convention which is often called by the Hoidy Toidy name application programming interface or API. Now in the end an API is just a fancy term for a set of conventions and certain underlying assumptions that you need to understand to use that library or program successfully. You might as well learn to follow APIs using simple types like integers before we go on to use APIs that have more complex structures as input output values where you have to pack the inputs and unpack the outputs. Inagers are very straightforward to use as calling arguments and return values. So let's look at the different systems that we had to use for the sample code in episode 1240. Well mod in the spreadsheet is a function because spreadsheets don't usually support infix operators other than basic arithmetic. Now spreadsheet mod functions follow the sign of the divisor. So the call 67 mod 7 gives you the answer for. Now that implies a quotient of 9 with the remainder for since 9 times 7 is 63 and when you add 4 you get 67 back. Now 67 mod minus 7 returns minus 3 which results from a quotient of minus 10 and remainder minus 3 since negative 10 times negative 7 is plus 70. Now for the doomsday spreadsheet this is good news because my formula used an offset function with expected values from 0 to plus 6 to look up the name of the day of the week from the offset value and here's the dependency. We use the function call mod x plus 7 to compute that offset value so we can always count on a calculated index that's in the right range. And that's pretty much all there is to say about the spreadsheet form of the mod function. Now the mod operator the percent sign in python is consistent with the spreadsheet but it's got a little extra twist that I wanted to report as well. Nothing to do with mods or did it. Now in python the mod operator the a percent sign b also returns a value with a sign that follows the divisor. So for this reason I didn't have to worry about whether I passed in a positive or negative x value in expression x percent 7. Now those of you who know python will see that my day of the week functions do their name look up the last step using a python list object and that object set up with Sunday at position 0, Monday at position 1 and so on up to Saturday at position 6. Now since the python mod operator returns non negative values for a positive divisor I didn't have to worry but there's a bonus application of mod in python and it turns out that python would return the same value regardless of the sign of the remainder as long as it's correct. Huh? That's right. Python list objects support negative subscripts whose behavior follows the operation of x mod minus 7 so the negative complement if you will of the positive subscript points the same day of the week as the positive subscript itself. Yeah. Well if you don't use python you might just want to skip this or fire up a python interpreter that's probably on your machine and try these things but I'll explain it and you can just sort of fast forward through this part if it doesn't make sense. Now when you're using subscripting on a 7 item python list let's call it my list. The first item is located at my list 0 and the last item is well where is it. If the sequence starts at 0 then the cocktail party is minus 1 so the seventh element is at position minus 1 plus 7 or my list position 6. So the positive values for the remainder work nicely as index into my list of day names. Very good but here's a special bonus. Negative subscripting analyst also works and it uses the convention that the last list item is my list position minus 1. The second the last is my list minus 2 and so on down to my list minus 6 but it will not work for my list minus 7. That doesn't work you would get an out of bounds error but that's not really a problem when you're calculating the subscript using mod whether you have the positive or non-negative or negative answers because what would have been pointed to by my list minus 7 is already pointed to my list position 0. Why is that? Well remember that minus 7 mod minus 7 is equal to 0 almost trivially because the two numbers divide evenly minus 7 divided by minus 7 would be 1 with no remainder with 0 remainder. So I don't have to worry about a mod function mapping me into my list minus 7 so I won't actually be trying to go there so this kind of code should be solid it should work. So the minus 7 case I don't really have to worry about it will simplify to my list position 0 and that's the value I wanted anyway. Now just to beat this to death let's say I'm running a doomsday calculation whose target date is on a Saturday. Now our storage convention puts this at my list position 6 the last element but for mod I just finished saying this location can also be addressed as my list position minus 1. Now if my call to x mod 7 had returned a negative value that corresponds to Saturday that value would have been minus 1. This makes sense because minus 1 and plus 6 are exactly 7 days apart. Have you thought about it? Minus 1 plus 1 is 0 plus 6 is plus 6. So we've counted off 7 units from minus 1 to plus 6. I hope you've convinced yourself of that. Not draw a number line and actually trace it with your finger or with a pencil and it will make sense. Now either value should legitimately point to Saturday and in a Python list it's actually work. And Python was pretty easy. Now for the mod operator in the BC program. Well I put in BC as the last minute thing. I did it in honor of Dan Washco's Linux in the Shell episode 25 which covered BC and that episode aired right about the time I was about to post my show. So like a dummy I decided to port my Python day of the week functions to using BC at the last second. And when I tested them I noticed that for some dates my functions got the correct answer but they failed on other ones and I knew something was wrong. It turned out there were a couple of things going on in my original functions. Now there were two issues I overlooked in what I call my naive port from Python to BC when I thought everything would work the same between the two environments. In BC the sign of the mod operator I'll call it xmod7 or x%7 in the code follows x. So I found out that when my reference states you'll have to listen to the doomsday episode to find out what those are. But when the reference states were earlier than the targets, x became negative in the expression xmod7 and by the convention in an array in BC this was wrong. Now this didn't come up in Python which is too bad because Python could have handled it. Now here's the second thing. I originally saved the days of the week, the names of those days in an array in BC but I couldn't get those shown in the display because BC wanted to return a number. So I made a last minute change to show the day of the week the name of that day as a side effect the function and my return value would be the offset I used to look that up. And the way I implemented the mapping from the offset to the day of the week was through a compound if statement, I checked if xmod7 is less than or equal to zero call it Sunday and so on up to if xmod7 is equal to six and then call it Saturday. So when I got negative values coming in it went through that incorrect logic on the first branch and always gave me the answer Sunday which was wrong about six out of seven times in row in the places where I was getting the negative values which was typically early in the year. Okay, now if you look carefully at the two day of the week functions that I included for BC you'll see that I solved this negative x problem by just adding some magic numbers to the original value of x in the xmod7 operations. Now those magic numbers are all multiples of seven which is okay but their values may seem a little bit arbitrary when you first look at it. I added a multiple of seven to x to get a nice positive remainder without changing the answer. Since I only had a short time to make my fixes I chose values that had an excellent chance to succeed. Arbitrary? Yes, but not completely arbitrary. Now here's an insight, there's a better way to have done it and I guess I figured out that some of you would probably have found it by now. I found it and I'm about to tell you about it. Now I wish I could say I had an ulterior motive in using these magic numbers in the xmod7 expressions so I could claim that I was trying to bait you into giving me feedback with your better solutions to the problem or find out whether there was anybody who saw through those algorithms and got it. But the honest reason is that I was on deadline and I stuck in numbers that would get the job done. Now here's a question. Is there anything I could have done to make those adjustments simpler? It's easier for later readers to understand and more robust all at the same time. Here's a spoiler alert, stop the podcast right now if you want to figure that out for yourself. I'll wait. Okay, you're back. Well that was easy, right? Once you start to play around with the functions a little bit you start to see how you could make this fix. I'll go through it in probably more nauseating detail than you'll want to hear. That's what the fast forward button is for. Now suppose we assign the answer to Xmod7 to the name Y. Now there are two possible cases for the value of Y. A is the easy case. Y is not negative so it's equal to 0, 1, 2, 3, 4, 5 or 6 and everything works. B is the needs help case where Y is not positive which is minus 6 minus 5 so on down to minus 1 or 0 and my original table look-up code for the final answer always returned Sunday. Now you may ask yourself what could I do to Y to make it work? Well here's a trial balloon, suppose we add 7 to Y whenever it's negative. That would fix things for Monday, Tuesday, Wednesday, Thursday, Friday and Saturday and since it was 0 and Sunday it wasn't negative and we're good. Well the first problem with this approach is it introduces an extra value check to see whether Y is negative and that's kind of a nuisance. But that's kind of an aesthetic objection. The second problem with the add 7 when Y is less than 0 fix is that you can screw it up if you try to move that check for negative values upstream by checking for negative X in the first place. Now if you try to anticipate a negative Y by checking X and then adding 7 when X is negative you've got a problem because you've just broken Sunday which is a position 0 in my setup so adding plus 7 to 0 takes you out of bounds. Now the add 7 adjustment is almost right but there's an even better way to do it and that's to add one more step. You get a better result that works for all X's without checking if you just always add 7 and then use Y plus 7 mod 7 as your subscript. Now if Y is negative adding plus 7 shifts its value into the range 1 to 7 which are all positive. So Y plus 7 mod 7 always gives the right answer and the right range is 0 to plus 6. The numbers 1 to 6 don't move the plus 7 goes back to 0 and you're all good. Now the added benefit of this adjustment is it doesn't screw up the answers when X is positive. When X is positive the expression X mod 7 gives you a Y value in the range 0 to 6. Adding plus 7 gives you an adjusted value from 7 to 13 and then Y plus 7 mod 7 moves the answer back into the range 0 to 6 and in the right places once again. So the adjustment is simple, it involves no checking in the program code and there are no magic numbers to conjure up or to have to test or worry about. Now that should help you to understand and use the spreadsheets and the little code snippets that I gave you with the Doomsday episode and understand why they are a little bit different in some places in different environments. Now I'm going to close with a couple of additional programming applications of the mod operation that might help you if you have programs that you're writing that do things a lot of times and you want to handle different cases. Now the first pattern is the every 1000th record pattern. Now if you do programming that has long processes that take a lot of steps, you may want to stop every few records to send a status message or make a log entry but you don't necessarily want to fill your disk with log messages every single step. So let's say you have a loop counter n, you could stop every 1000 records with a simple line of code say that your status message or log entry is done with a function called show underscore status. So your code would be in the middle of your loop if n mod 1000 is equal to zero. So if I've got a multiple of the 1000 then show status and maybe include n if you want a report where you are and some other arguments and that will make your log entry every 1000 records. Now if your loop starts with zero it might put out a log entry immediately but you can adjust for that. And then there's a kind of a common pattern I run into it's called the every other record pattern. I frequently run into situations that lead to what I'll call even odd processing where you have to switch between two handlers at every other record in the file or maybe an event in a simulation. Let's suppose you have some kind of a thing that can change states from on and off at each step. I mean even printed books have left and right hand page formats that are different in a way that helps readers but it makes things a little trickier for the types that are in printer. That's the kind of thing I'm talking about. Now when you need to distinguish between even an odd parity the mod function handles that very naturally. After all if n is even then n mod 2 would be zero and vice versa. And likewise if n is odd then n mod 2 is one. Now with a divisor of two life is simple there's only two possible outcomes. Now I can shuttle back and forth in a read loop with index n pretty easily using the mod function or mod operator. If I have two functions that I'll call do when odd and do when even that I want to run when n is odd and even respectively I can just write the compound if statement if n mod 2 is equal to one then do when odd else do an even done. Very simple just put in that little snippet of code and I'm able to handle every other record properly. And finally there's the scene one cycle scene of all that you run into where the input data spans several input lines in a predictable way with the same number of records for each entity that I'm reading. Then I could use mod or an equivalent to tell my code to do something each line in that cyclical pattern. Now let's say I have a pattern of eight items per cycle and loop variable n and for the simplicity I had several cases that collapsed into one function call. So first thing I do when I come through my loop is I compute my offset equals n mod 8 because I don't want to keep doing the division every every for every time I have to check the value. And then I go into my statement and then I go into my if statement and that's if my offset equals zero then I'm going to get name and I call that function and it will get the name and store it somewhere. And then in my pigeon programming code I'm going to say else if my offset is greater than zero but less than six then I'm going to call my function oh get details and I'll throw in the value of my offset is the first argument and then maybe some other arguments and then I'll handle the case where my offset is equal to six so that's else if my offset equals six then I'll get city state and zip let's say very U.S. Century come sorry I could have said postal code and so on but I was lazy and then else let's say I'll get the phone numbers and that would handle the case where my offset equals seven and that's all the values that you need to check those are the only possible outcomes for an integer being divided by eight and checking the remainder. Okay well there are other applications of integer division and creative uses of the quotients and the remainder is in programming I think these examples will be enough to get you started. I think it would be not too long before you'll be creating your own useful examples from your own work or maybe from hobby projects or play so I think we can safely leave this topic and move on to the conclusion and I'm going to talk about some more things but I think I've given you a lot to chew on I mean you can take this discussion of mod and remainder is further to talk about nice techniques for factoring big numbers and I'm talking about either huge numbers or numbers that are big to be playing within your head or for working with number bases other than ten or predicting the form of repeating decimals and that kind of thing and that exploration would really use the same kind of techniques that our teachers showed us when we were in school I guess between the ages of six and twelve rather than naming US centric great great numbers or names but I think we're going to leave this here for now I think it's been enough for one show where are we going next well I think the next thing we're going to do I'm going to probably leave the recreational math theme behind and look into a couple of listener requests for what I would call practical math topics before I start looking at things that I wanted to look at in terms of math and statistics software now probably procrastinating a little during the summer by recording one or two shows on how I got into computing partly because hpr needs shows that I can produce quickly and partly to buy time to figure out how to explain some things in an audio only podcast format well having said that if mr x can do a comprehensive two part show on soldering I think there's hope for this planned math for the rest of a series to work so that to end for today and now it's your turn to record your show for hacker public radio your ideas and projects podcasted thanks for listening you have been listening to hacker public radio at hackerpublicradio.org we are a community podcast network that releases shows every week day Monday through Friday today's show like all our shows was contributed by a hpr listener like yourself if you ever consider recording a podcast then visit our website to find out how easy it really is hacker public radio was founded by the digital dot pound and the economical computer cloud hpr is funded by the binary revolution at binref dot com all binref projects are proudly sponsored by linear pages from shared hosting to custom private clouds go to lunar pages dot com for all your hosting needs unless otherwise stasis today's show is released on the creative commons attribution share a life lead us our lives