- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
How do you get 40.9599609375 with integer Maths? It's probably some embedded system assembler magic.
Admin
And now for something completely different: the Y25k7 problem.
Admin
Also:
For April, June, September, November it is not checked if register3 is >= 1.
And register3 is suddenly called r3 at the end of the function, but I guess this is due to the Java translation ...
Admin
'How do you get 40.9599609375 with integer Maths?'
Obviously you don't, directly. What's happening is that register 5 is being bit-shifted right 10 times and subtracted from itself. A right bit-shift is equivalent to dividing by 2, so this is (Reg 5) - (Reg 5 / 1024). Since we're talking integer maths, if Reg 5 contains 41 then it will still contain 41 afterwards, not 40.9599... etc, but you get the picture.
I used to love doing this sort of thing. 8086 could handle multiplication and division but it was so expensive in processor time that you'd go to great lengths to avoid it if possible.
Admin
Admin
The bit mangling effectively multiplies the year by 41 then subtracts one 1024th of that result. If we revert to using floating point for a moment, and take year 1000 as an example, multiply by 41 and then subtract 1/1024 of 41000, we get 40959.9609375, and if we divide that by 1000 to recover the true multiplier, we get 40.959960937.
That's how we get such a multiplier on an integer-only machine.
None of that explains how we get to such a number, nor why we want to treat any days at all in year 0 as valid.
Admin
I\ld think this case is covered by the register3 >= 29 check...
Admin
Oh, and there have been 32-bit architectures with integer and floating point multiply and divide instructions since at least as far back as the first IBM System/360s. You know, nearly 50 years ago.
Admin
Admin
Admin
Or maybe not... (my mistake)
Admin
TRWTF is the parameter order: month, day, year.
CAPTCHA: sin0
Admin
Yes it is, it's bigger than 28 already.
Admin
I really don't see a WTF, this is a good and efficient ASM implementation of the generic date validation math for leap years, considering the limitations.
I don't see how the math has anything to do with the year being limited to 25600. Looking at the bit shifts, that would use only 21 bits, and we're told the arch is 32 bits, so that's not the issue.
I know our calendar will be off for 1 full day in some 3300 years with our current leap-year scheme... still doesn't match the 25600 number.
Admin
Still looking for TRWTF?
It's here: "He found it fascinating, and spent a great deal of time examining its innards."
This means that this clever bit of code was great, but not sufficiently documented to allow it to be supported if there ever turns out to be a bug or a change to the requirements.
Admin
You might do, but we're talking about register shifting here which isn't quite the same. If you start with 16 as an example, shift right once -> 8, twice -> 4, etc, until you have 1. Shift once more, or any number beyond that, and you have zero. So what we have is 41 - 0, which is still 41.
Admin
The mistake is that in 1582 there was no October 5th to October 14th, but there were February 29th in 1500, 1400, ...
But, of course, TRWTF is translating assembler to Java.
Admin
One approach that could be used is to use a routine that calculates the day of the year. Then for day-month-year, subtract the day of the year for 1-month-year from 1-month+1-year. If month is 12, subtract 1-month-year from 1-1-year+1.
Admin
I think we should introduce a check, if register3 is bigger than 1 if it is bigger than 28. Just to be sure, you know?
Admin
Since we can't divide by 100, we need to divide by something easier, in this case, 4096.
So we multiply the century by 40.96 (approximately, which is why the calculation doesn't work after 25699) and look to see whether it is a multiple of 4096.
Admin
Admin
where is register1?
Admin
Admin
Admin
We wanted to see the Assembler source code.... It would have been far more compact thant that bloated java code
Admin
Indeed. I was just giving an example of why you don't round down. It continues to work however large the number is.
Admin
Admin
There is even one occation of Feb 30th. 31st of Feb is probably a hoax, but there are some vague references.
Admin
This reminds me of some so called programmers that I wanted to strangle on 1-Jan-2000. These cretins had written a job scheduling program that our business totally relied on, and it keeled over due to Y2K issues. I had to get up, seriously hing over, and go in a to get it back on the air. Looking at their code, the yahoos had put in lots of code to support 5 digit years, but had muffed the simple changes needed for the year 2000. These idiots thought their code was going to survive into the year 10000...
Admin
I pity the poor soul. He had to write in assembler on such a machine. Now that's TRWTF!
Captcha: damnum. Damnum that machine!
Admin
I pity the poor soul. He had to write in assembler on such a machine. Now that's TRWTF!
Captcha: damnum. Damnum that machine!
Admin
Admin
Yeah, but there where a lot of other chips that didn't to save space on the die and make them attractive to the hobbyist / Micro market.
Admin
And on most of the others it was less costly in cpu cycles to do a bunch of sums, subs and shifts than a single division.
Admin
Yes, there were, but as others have commented it was hugely expensive in terms of CPU cycles. I used to sit with the 8086 bible in front of me working out how to shave cycles here and there. Given the sort of tasks you would typically do in assembler complex maths wasn't really required. Rather than multiply by 10, for example, it was way quicker to do bit-shift three left (multiply by 8) and two adds to get to your answer.
Bear in mind, also, the speed of processors at the time. I started off using assembler to write to the screen buffer of a Superbrain, an all-in-one pc which used a 4MHz Zilog Z80 processor. Shaving those processor cycles made a very visible difference to the speed at which that happened. Nowadays you probably wouldn't worry. Much like the profligate way data is stored: the first time I saw XML I couldn't believe the waste of space, having come from an era where you packed data in as tight as possible because all you had for storage was 720k floppy disks! Happy daze!
Admin
1453 defeat of Constantinople 1485 battle of Bosworth Field 1492 Christopher Columbus tries to outsource programming to India, but accidentally finds the first Nagesh. 1517 Programming Reformation - Richard Stallman publishes his 95 theses about the differences between cathedrals and basars and invents open source software.
Admin
Exactly, if you have to write code that looks like a WTF at first glance because of weird scenarios, you better add comments, or it won't last long.
Admin
Admin
The original comment is from someone whose first language isn't English (of any sort).
What he is saying is that, for months with 30 days, there is no test that the day number is >= 1. That test should probably have been done before the case statement, not after.
Admin
TRWTF is introducing r1 and r2 outta nowhere
Admin
The branch for evaluating April, June, etc is only visited, if the day is gte 29. Else, there is a test for the day being at least 1. So there is no edge-case:
Admin
Admin
Everyone who thinks there's no test for >= 1 for 30 day months is misreading the code.
The switch statement is only reached when the day is 29 or greater. All others fall through to the final check at the bottom:
return r3 >= 1 && r3 <= 31;
The comment above it, "// 31-day months," is misleading and was obviously added in the java translation. It should say "31 day months and all days < 29".
Admin
Admin
Admin
Now that the this has been batted around a bit, I'll reveal the rest of the story...
The aim is to multiply the year by 40.96 (the 40.9599609375 is due to limitations of the math used and the multiply depends on rounding to get the correct 40.96 multiple).
And the point of 40.96? That scales the centuries to be multiples of 4096. So 1900 becomes 77,824 and 2000 becomes 81,920. And the point of that? Well, you have to look at it in binary....
Let's look at 2000 first; 81920 in binary is:
0000 0000 0000 0001 0100 0000 0000 0000
The 12 binary zeros on the right reveal that this year is divisible by 4,096, which is 40.96 * 100, so that's an even century.
But if you're astute, you will note that there are 14 zeros on the end. That means that the number is divisible by 16,384, which is 4 * 4096, which is 40.96 * 100 * 4 or every 400 years.
Got that?
Okay, now look at 77,824:
0000 0000 0000 0001 0011 0000 0000 0000
There are 12 binary zeros on the end, so this is a century year, but there are not 14 binary zeros on the end, so this is not a year divisible by 400.
I looked at this off and on for about a week before light finally dawned. And I no longer have the actual code; but the concept will stick with me forever.
Admin
When I once told a client that 3rd party software we were using had a Y10K problem (hard-coded 4-digit years), he answered: "I hope this becomes a problem."
Admin
Looks like widdle baby threw a tantrum and pooped his pants all over the thread.
Admin
Wow, someone (ssddfdfsdf) has discovered ^A (select all)! Congrats, and welcome to the community of computer users!
Admin