Ruby and floats

● ARCHIVED · READ-ONLY
Started by Napoleon 8 posts View original ↗
  1. f = 0.0100.times do f += 0.01 p fendProduces:

    0.01

    0.02

    0.03

    0.04

    0.05

    0.06000000000000000

    0.07

    0.08

    0.09

    0.09999999999999999 # <<<<<<<<<<< what?

    0.10999999999999999

    0.11999999999999998

    0.12999999999999998

    0.13999999999999999

    0.15

    0.16

    0.17

    0.18000000000000002

    0.19000000000000003

    0.20000000000000004

    0.21000000000000005

    0.22000000000000006

    0.23000000000000007

    0.24000000000000007

    0.25000000000000006
    Wow... I can't increment a float from 0.00 to 1.00 without rounding problems by JUST adding?

    How do I solve that? I prefer not to count from 1 to 100 and then divide by 100. Also preferably without rounding it every iteration.
  2. Can't you just do the following?

    def test f = 0.0 100.times do f += 0.01 p f.round(2) end endOr maybe use sprintf?
  3. Floats in ruby are imprecise. I suggest some background reading: http://en.wikipedia.org/wiki/Floating_point

    When dealing with floats always try to keep the original numbers. They can help greatly in decreasing the error propagation.

    For integers we have Bignum. Maybe there is a BigDecimal or something equivalent for floats? If you research this please let me know of your findings.

    *hugs*

     - Zeriab
  4. Floats are notoriously imprecise like this, pretty much universally.


    http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html


    https://github.com/rdp/ruby_tutorials_core/wiki/ruby-talk-faq#floats_imprecise


    http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems


    Why exactly are you iterating here anyway? If you are incrementing a number, float is probably not the best way to go. Even if you do, you need only round the resultant number. After 100 iterations, the rounding errors account for less than 10 ^ -15 of the total number with a loss of precision of 10 ^ -13 considering the significant digits of all operations, which is completely insignificant (another few trillion iterations and you might be in trouble) - that is, unless you are comparing the resultant calculated number directly with other floats. If you are, you need only round it once. If you are using it as a display value (eg. a stat or something that the player needs to see directly), just control the precision of what is displayed and ignore the small rounding error and/or just use whole numbers and convert it to a float right before displaying it.
  5. I never had this problem in C# unless I worked with divisions or really really huge numbers (larger than 32 bit floats) perhaps or some complex stuff. But in C# I remember this to work. Ruby however rolls over and dies at just 9 iterations with just 3 decimals. I am totally... Shocked... I expect 0.01 to be followed by a infinite amount of zero's and not a semi-random number (not totally random, always the same sequence) somewhere at the end that comes out of nowhere.

    I understand that floats are imprecise in Ruby due to rounding, divisions or when they get too big, etc. But there is no rounding here. This feels so wrong.

    @stretch_progress += 0.01 # <<< bugs. # Old code@stretch_progress = (@stretch_progress + 0.01).round(3) # <<<< This is... Silly. But sadly works. Even if @stretch_progress is a 'clean multiple' of 0.01Some tests:

    0.01 + 0.01 == 0.02 # good
    Code:
    f = 0.0100.times do  f += 0.01endp f # 1.000007 and 0.0999999 at the 9th iteration instead of 0.09.
    Code:
    f = 0.09.times do  f += 0.01endp f # 0.09  (now it DOES work, I only changed the max. number of loops)
    Code:
    a = 0a += 0.01a += 0.01a += 0.01a += 0.01a += 0.01a += 0.01a += 0.01a += 0.01a += 0.01p a # 0.09
    Yes I compare the numbers and I noticed that the comparison always failed. There is some kind of pseudo-random number at the end.

    This almost wants me to make my own float with a set number of digits which are always accurate for adding numbers (which is easily possible). Forcing every number after x digits to always be a zero no matter what (basically automatic-rounding). Floats are so extremely imprecise (unless I do something wrong) that you should never ever work with them unless you strictly round them everywhere or just never ever compare them. I really did not expect this to happen with just 3 decimals and 9 iterations and by simply adding the numbers.

    EDIT:

    I'm incrementing a percentage between 0.00 and 1.00.

    And BigDecimal is not included in RGSS. It seems to 'have been left out' of the library. Both the class and the required file are not present. In theory BigDecimal should solve the problem: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/bigdecimal/rdoc/BigDecimal.html

    BigDecimal provides similar support for very large or very accurate floating point numbers.
  6. That has nothing to do with Ruby. Read the linked sites and pretend to understand IEEE 754 floating point like most programmers do.
  7. I read the sites and I even read some before I even posted here. But no I do not understand but I will indeed pretend I will :p . Good one.

    I found http://floating-point-gui.de/basic/ which explains it a bit simpler for 'people like me'. They also advise to use a custom decimal type as one of the workarounds.
  8. Assuming you specifically want 2 decimals you already have given the easiest solution

    Napoleon said:
    How do I solve that? I prefer not to count from 1 to 100 and then divide by 100. Also preferably without rounding it every iteration.
    Yup, use an integer internally for all your calculations that is 100 times larger than the actual number it represents.

    Whenever you actually need the decimal number you create a float based on that integer. Be sure to keep the integer

    This way is much easier than keeping track of the maximum possible error margin.

    *hugs*