• Matthew (unregistered) in reply to Bezalel
    Bezalel:
    I haven't figured out why the fact that it is VB is so important. The only thing I could think of is the fact that Int() returns a Variant (I think of the same type as the parameter) and not an Integer but I don't know why that would matter.

    VB has nothing to do with it. All the postings about bankers rounding, VB etc etc have completely missed the point. This is a floating point issue, pure and simple.

  • justme (unregistered) in reply to darwin
    darwin:
    justme:
    huh? no. You cannot multiply .3333~ by 3.

    Of course you can. Why wouldn't you be able to multiply an infinite series by a number? It's just the equivalent of multiplying each term of the series by that number.

    And .9999... is equal to 1, of course, because it's just another representation for the series 9 / 10^i as i goes from 1 to infinity. Two different notations for the same thing.

    You can't because a number is infinitely repeating -- where do you start multiply?

    And no, 9/10^i -> 0 as i goes to infinity. I really doubt your mathematical abilities.

  • blah (unregistered) in reply to justme

    In this particular case, why do you need to know where to start multiplying? Obviously, if you wanted to actually write this out by hand completely, you couldn't, but some simple logic can bring you to the answer.

    After all, if you were to do this by hand, you'd break down into an infinite series of 3 times 3 for each digit, which is 9. There's no carrying involved, so none of the operations is going to affect any other digit in the result. 3 is also a one-digit number. For 13, you'd have to multiply by 3 and then by 10 and add together, but this isn't necessary for 3. Each individual 3x3 multiplication affects one and only one digit in the result, and a different one each time, so why can't we assume that 0.33333 (repeating) x 3 = 0.99999 (repeating). After all, it doesn't matter if we multiply 3x3 an infinite number of times, does it? It's always going to equal 9.

    So, thus, given the following:

    We know that 1/3 * 3 = 1, because you multiply the numerators and denominators and then reduce. (1/3 * 3/1 = 3/3 = 1).

    But we know that 1/3 = 0.333333 (repeating). You would accept that, right?

    Well, if you accept that, then consider the following:

    A = 3 B = 1/3 (as a fraction) C = 0.3333333333333 (repeating)

    Since B = C, then AB = AC, right? Even though AB = 1 and AC = 0.999999 (repeating)?

    So, If 1 != 0.999999 (repeating), then I must have missed something in algebra.

    Feel free to repeat the example with 0.1111111 (repeating) x 9 vs. 1/9 x 9.

  • justme (unregistered) in reply to blah
    blah:
    But we know that 1/3 = 0.333333 (repeating). You would accept that, right?

    Well, if you accept that, then consider the following:

    A = 3 B = 1/3 (as a fraction) C = 0.3333333333333 (repeating)

    Since B = C, then AB = AC, right? Even though AB = 1 and AC = 0.999999 (repeating)?

    So, If 1 != 0.999999 (repeating), then I must have missed something in algebra.

    Feel free to repeat the example with 0.1111111 (repeating) x 9 vs. 1/9 x 9.

    I don't really want to argue this any further.

    If you know how to multiply infinite repeating nubmers, tell me: what's 0.9999~ * 0.999~ is it 2 or 1.9999~ or is it 1.999~99971? (with tilde means repeat). If you multiply infinitely many times will you get 1 or get 0?

  • justme (unregistered) in reply to justme
    justme:
    blah:
    But we know that 1/3 = 0.333333 (repeating). You would accept that, right?

    Well, if you accept that, then consider the following:

    A = 3 B = 1/3 (as a fraction) C = 0.3333333333333 (repeating)

    Since B = C, then AB = AC, right? Even though AB = 1 and AC = 0.999999 (repeating)?

    So, If 1 != 0.999999 (repeating), then I must have missed something in algebra.

    Feel free to repeat the example with 0.1111111 (repeating) x 9 vs. 1/9 x 9.

    I don't really want to argue this any further.

    If you know how to multiply infinite repeating nubmers, tell me: what's 0.9999~ * 0.999~ is it 2 or 1.9999~ or is it 1.999~99971? (with tilde means repeat). If you multiply infinitely many times will you get 1 or get 0?

    I should said is it 1 or 0.999~ again or 0.9999~~9971.

  • blah (unregistered) in reply to justme

    [quote user="justme"]I don't really want to argue this any further.

    If you know how to multiply infinite repeating nubmers, tell me: what's 0.9999~ * 0.999~ is it 2 or 1.9999~ or is it 1.999~99971? (with tilde means repeat). If you multiply infinitely many times will you get 1 or get 0?[/quote]

    I should said is it 1 or 0.999~ again or 0.9999~~9971.[/quote]

    I really don't know why this is so difficult to understand. As for multiplying numbers with an infinitely repeating decimal portion, did you note I did say it can't be done by hand? I said you can logically infer the answer in some cases, specifically where the following two conditions are true:

    1. Where one factor has an infinitely repeating portion and the other factor has only one significant digit, or is a single-digit number. (0.99~ * 0.99~ doesn't meet this condition.)
    2. Where there will never be a need to carry. (0.99~ * 0.99~ breaks down into a infinite number of 9*9 equations. This is 81, and it should be obvious carrying the 8 is necessary.)

    But of course, 0.99~ * 0.99~ = 1, because 1*1 = 1. Since you refuse to accept that 0.99~ = 1 (a fundamental mathematic principle), and I don't feel like educating any further, I'll just cite:

    http://www.newton.dep.anl.gov/newton/askasci/1995/math/MATH070.HTM

    http://mathforum.org/library/drmath/view/55845.html

    lurl]http://polymathematics.typepad.com/polymath/2006/06/no_im_sorry_it_.html[/url]

    I'd list even more, but I'm sure you can use Google yourself. If you still refuse to accept this in the face of so much evidence, there's little I can do about it.

  • JT (unregistered) in reply to vern

    Heximal

    Found it hiding in hexadecimal ;~)

  • (cs) in reply to Jimmy Jones
    Jimmy Jones:

    Re: Round and Round 2007-01-21 04:03 • by Jimmy Jones

    Eirik:
    You should never ever use == with floating point numbers, every serious coder knows that.

    Wrong.

    float x = 1.23; float y = 1.23;

    if (x == y) { // This works perfectly... }

    Eirik:
    It because they are represented with a binary exponential.

    Completely irrelevant.

    Eirik:
    The conversion between binary and decimal very often lead to slight inaccuracies.

    Maybe the problem is that you're doing conversions where you shouldn't be.

    Your example of:
    Jimmy Jones:
    float x = 1.23; float y = 1.23;

    if (x == y) { // This works perfectly... }

    ..does work perfectly because you have defined both values under very controlled conditions. What happens in the real world is a different matter completely. Eirik is correct and you have unjustly criticized him. He is right, there are very subtle interactions that occur in the floating point units of a CPU. You cannot exactly compare values with the "==" operator that have come from other mathematical steps, or real-world sensor data. Saying that he is doing un-neccesary conversions also isn't useful either, this algorithm does require the 'temp' multiplication step which is, in fact, the source of the error.

    So for everyone that seems to be missing the point on this WTF, here is the answer:

    1. VB isn't the problem. This error will occur in any language. 1b. VB's 'Banker' or round to even/odd rounding as people have been stating isn't really a factor in this particular issue. If that is in fact how VB does it, then it could be an issue in other circumstances if that isn't what you wanted. But round-to-even/odd is typically more desireable in general because it balances out the bias that occurs in classical rounding because .5 is perfectly in the middle and creates an upward bias if you don't round to the even or odd value.
    2. The issue happens in the FPU itself. It is an artifact of representing Base-10 Decimals on a binary floating point unit. With the critical added factor...
    3. ... of performing a base 10 multiplication, and expecting a base-10 perfectly round answer on a base 2 FPU. Where things go wrong in this example is the line that reads: "temp = number * factor + 0.5" The multiplication introduces a tiny amount of inaccuracy that prevents proper rounding later on. Also, the "+ 0.5" is a fudge factor that the author tacked on, and shouldn't be used.

    Evidence: I ran this through my favorite language 'Python' to get the same results the author had. I will show just the results of the critcal step:

    temp = 39.995*100 print "%.10f"%(temp) 3999.5000000000

    ....looks good....

    round(temp) 3999.0

    ....oops!

    print "%.20f"%(temp) 3999.49999999999950000000

    ....oh wait!

    Solution: (This is the Python equivalent, and it goes in the code right after the line "temp = number * factor") eps = .000001

    fCloseToHalf = (temp - math.floor(temp)) - 0.5
    if (fCloseToHalf > -eps) and (fCloseToHalf < 0):
        temp = round(temp) +1
    else:
        temp = round(temp)
    

    ... but this isn't a really good answer, because you have to hand-hold each time you do any operation on the floating point number. You are better off using a different representation, which is what the original author did.

    To summarize, floating point numbers suck if you want values that round out nicely. This is a problem especially with currency because people get bitchy when you lose a cent here or there. Use a string representation, separate dollars and cents as integers, or use a decimal type if possible. For most applications, floating point numbers either don't need to be rounded, or the rounding isn't going to make a major difference. The big lesson here is to never trust a floating point number to be exactly what it reads as when printed with a 'printf'. Don't try to compare a result with the == operator. If you think a value should be an integer, compare it within a range that is very close to the integer you are thinking of. The amount of error possible is known as epsilon, and is defined for the FPU you are using. Keep in mind that the error can compound over multiple operations.

  • Michael Moore (unregistered) in reply to Jimmy Jones

    double x = 95.0 double y = (19.95 - 19.00)* 10.0 * 10.0;

    if ( x == y ) { //this fails miserably. }

  • (cs)

    The "Round the Round" 24 hour event is a team relay mountain bike race, beginning at noon on Saturday and ending at noon on Sunday. Teams compete for medals, prizes and bragging rights.Anyone who can ride a bike can do this….your team decides how many laps each person does…one or a whole bunch. So bring your camping gear, bike gear and whatever else will keep you going for 24 hours... then come on out and get dirty with us!

    real estate

  • Ian D (unregistered)

    Here's my version ... which seems to work okay:

    Public Function roundTo(ByVal number As Double, ByVal digits As Integer) As Double
        Dim temp As Double
        Dim factor As Double
        factor = 10 ^ digits
        temp = (number + (0.5 / factor)) * factor
        roundTo = Int(temp) / factor
    End Function
    
  • Sean (unregistered) in reply to Anon
    Anon:
    vern:
    If we were using a number system that was say, 6-based instead of 10-based, we could show 1/3 with a finite number of digits after the '.' <-- we probably wouldn't call the '.' a decimal anymore either... anyone know the name of a 6-based number system? 8 is octal.

    Hexal?

    the prefix "hex" would work, but as we already have Hexadecimal, as well as "hex" being greek and "octa" being latin, we are better off using "sexa" as in "sexal".

    and here is the ref: http://en.wikipedia.org/wiki/Numeral_prefix

    Reading that back just makes it sound inappropriate...

Leave a comment on “Round and Round”

Log In or post as a guest

Replying to comment #:

« Return to Article