For that particular goal, it’s not the number of divisors in the base that matter, but the number of unique prime factors. (So, base 36 is no improvement over base 18, or even base 6.)
Wait, I wasn’t laughing in the first place… I’m all for hexadecimal over octal. My post was sincere, not mockery.
I doubt that base 36 would be so easy. Can you imagine having to memorize your times tables in base 36? Or even your add tables, for that matter. Lower bases, in the 8 to 16 range, would have the advantage there.
And could you imagine a more horrid choice of base than
2.71828182845904523536028747135266249775724709369995957496696762772407663035354 ?
Who would EVER choose a fractional number (let alone one with LOTS of decimal digits) as a base?
I wrote a little essay about THAT not long ago, harping on the fact that so few programmers have a clue about this. CookingWithGas and Chronos entered posts agreeing, and we got into a discussion there about how best to compare floating-point number to get programs to do the right things.
Well? How many of you programmers out there HAVE done this, or similar, exercise at least once in your career? I keep harping on this because of the non-ending trouble I have had in working with, or supporting, other people’s code that does this wrong.
ETA: I’ve also noticed that:
addEmUp = tenth + tenth + tenth + tenth + tenth + tenth + tenth + tenth + tenth + tenth ;
doesn’t always produce the same result as:
addEmUp = tenth * 10.0 ;
Go figure. Might have something to do with compiler code optimization or something.
To be fair, there are natural reasons why one might want to use a finite datatype for many purposes, and there aren’t any finite ordered fields, so something was bound to go bizarre from the start…
As an aside we have base 12 (it’s “eleven” and “twelve”, rather than "oneteen and “twoteen”, and we count by dozens in many circumstances) and base 60 mixed thanks to finger counting as well:
Count the phalanges on one hand with your thumb - you count to twelve once. Mark that dozen by flipping up your thumb on the other hand and keep counting (One dozen one, two …) and after that dozen flip up another finger on the other hand. Fill up that hand and you have sixty.
We used to teach a subject called numerical methods - which was a one semester course in basic computer numerical algorithms. Lecture 1 was about machine epsilon. However the subject hasn’t been offered in a very long time. This is not a good thing. (There was a follow up course on numerical analysis which taught the core stuff, the methods course really taught students enough that they wouldn’t get into trouble doing stupid things. Nowadays they do get into trouble doing stupid things.)
One might note that there is nothing special about computers and binary notation that makes it susceptible to these problems. You can cook them up in any base. (Which is essentially what Indistinguishable said above.)
They are different expressions. The first one is the sum of exactly 10 copies of tenth. The second expression is the multiplication of the floating point number 10.0 by the floating point number tenth. These expressions are different for exactly the reason being complained about. 10.0 is not the same number as 10. Many languages will automatically convert 10 to 10.0 when needed in a mixed mode expression. But not all - some require explicit conversions. And it is well understood that the conversion is fraught with issues. In languages with conversion rules 10 * tenth would be silently converted to 10.0 * tenth. But the expression tenth + tenth + tenth + tenth + tenth + tenth + tenth + tenth + tenth + tenth will not be.
BTW here is a page from a book giving the rationale for design decisions for the Ada programming language. It was written by the lead designer. This page talks about model numbers (numbers which are required to be represented exactly on a machine to be compliant with the Ada specification) and safe numbers (numbers which can be represented exactly on a particular[del]any given[/del] machine). Here is a page on the same topic from the reference manual.
Ada has long since fallen out of favor, and I think these terms were coined for Ada rather than being industry standard, but the concepts are universal.
I can see that tenth * 10.0 might produce a different result than tenth + tenth + …, but I would expect neither of them to compare exactly equal to 1.0 (ETA: And I expect that 1.0 would always be represented correctly and exactly.)
And I would always expect any (reasonably sized) integer, when converted to a float, to be exact. So tenth * 10 should be identical to tenth * 10.0 providing that the language allows it at all.
When I took Computer Science classes at U. C. Berkeley in the early 1970’s, the major also required a Numerical Analysis course (in the Math department), although I never took it. So what minimal understanding I have, I’ve just picked up over the years. That class is a full semester (or quarter) of heavy-duty mathematical number-crunching. But for the non-so-mathematically-inclined, I think that all basic programming classes should at least teach some basics, for maybe two or three lectures’ worth or so. As far as I know, this is not done.
I remember being utterly gabberflasted when a friend first pointed out to me that 0.1[sub]10[/sub] is a non-terminating [del]decimal[/del] thingy when expressed in binary.
I really think the above programming exercise that I recommended (which I invented myself) should be a required exercise for all first-semester programming students, regardless of what programming language they are using. (I vaguely remember having tried it with Visual Basic, and the numbers compared equal. Does VB use some kind of finagle-factor in comparing floats, to “protect” the naive programmers who use VB?)
Google won’t let me see either of those pages. (Do I have to be a subscriber or something?)
If only we had had a base-twelve numerical system when we invented the metric system. Then it would be the best of both worlds… “I’ll have a quarter-kilo of lentils and a third of a kilo of beans…”
There are 10 kinds of people on the SDMB, those that understand what’s going on in this topic and those who don’t
I teach beginning programming at a state technical college, and yes, we do cover this topic every time we discuss conditional operations. It takes an actual run printing out the results of an if statement (in both Java and C++) for them to be aware of the problem. It’s also one of my test questions on the midterm exam!
In Visual Basic and in C-Sharp, Microsoft has both the double format for the binary approximation of a floating point number, and a decimal format which keeps the result in pure decimal form. In fact, the formatting codes for decimal uses ‘M’ for money. We discuss Office Space when talking about double and decimal - as programmers, this is one way they could get rich!
Yes, 1.0 will represent exactly. Where you may still get into trouble is when using it in an expression. The implementation of the floating point hardware comes into play. 0.1 uses all the bits, and the least significant bit becomes a problem.
Yes, where “reasonable sized” means that you can represent it within the mantissa of the floating point number without truncation. That gets you 24 bits in IEEE single precision. However again, you remain at the mercy of the floating point hardware for the exact result. The least significant bit could easily vary. Usually the FPU will calculate the result to more bits of precision than the base width and round the result. However the precise rounding rules can vary, and you can’t rely on the value of the LSB being identical on all platforms.
I have never seen a system where you could not depend on exact integer->float conversion for smallish ints. I don’t understand where the LSB comes into play. If you try to convert 16777215, the computer should, without exception, give you a float value of 0b01001011011111111111111111111111. There is no uncertainty in the LSB because there is no rounding to be done.
Now if you had tried to store 16777217, then maybe on some languages/OSes you get 0b01001011100000000000000000000000 while on others you get 0b01001011100000000000000000000001, depending on the rounding behavior.
Even so, the actual machine shouldn’t make a difference–this is a question of how the language or OS libraries convert the text representation of the float into the binary representation. That detail has very little to do with the hardware it runs on.
Of course, once you multiply the numbers, all bets are off, because multiplication in general requires a doubling of precision for exact storage.
Right – in IEEE single-precision format, there are 23 bits in the significand, with an implied 1 at the beginning, and an additional sign bit, so you can represent all integers from -(2^24 - 1) to (2^24 - 1) precisely. But any fraction whose reduced denominator is not a power of 2 (such as 0.1) can’t be represented precisely.
I was curious about this, so I looked up the Wikipedia entry on Babylonian base 60 numbering and interesting enough, the symbols from 1 to 59 are actually in base 10.
Counting to something more than ten on your hands, say to 100 or 1,023, isn’t a hardware problem it’s the software.
CMC fnord!
How do you get 12 by counting phalanges? I have five fingers and toes on each hand or foot.
Exactly. That was my point. The question was why 10 * 0.1 behaved differently to 0.1 + 0.1 + … + 0.1 - and it is the multiplication of 0.1 by 10.0 versus 10 floating point additions that gets you there. On reflection, my use of the word “result” was probably not as obvious as it might have been. “Result” referred to the result of the expressions - not the conversion from int to float.