I have read these:
They explain "how". I'd like to know why it's different across these languages. I expected similar results given the same input.
test.js
#!/usr/bin/env node
var nine = 9.0;
var pointOhOhOne = 0.001;
var result = nine * pointOhOhOne;
console.log(result);
test.java
public class test {
public static void main(String[] argv) {
double nine = 9.0d;
double pointOhOhOne = 0.001d;
double result = nine * pointOhOhOne;
System.out.println(result);
}
}
test.c
#include "stdio.h"
int main() {
double nine = 9.0;
double pointOhOhOne = 0.001;
double result = nine * pointOhOhOne;
printf("%f", result);
}
test.rb
#!/usr/bin/env ruby
nine = 9.0
pointOhOhOne = 0.001
result = nine * pointOhOhOne
print result
test.py
#!/usr/bin/env python
nine = 9.0
pointOhOhOne = 0.001
result = nine * pointOhOhOne
print result
results:
ruby 0.009000000000000001
python 0.009
node 0.009000000000000001
java 0.009000000000000001
c 0.009000
gist: https://gist.github.com/reklis/6694ad5fb01991a79a1a
It's a problem caused when the internal representation of floating-point numbers, which uses a fixed number of binary digits to represent a decimal number. It is difficult to represent some decimal number in binary, so in many cases, it leads to small roundoff errors.
Because often-times, they are approximating rationals that cannot be represented finitely in base 2 (the digits repeat), and in general they are approximating real (possibly irrational) numbers which may not be representable in finitely many digits in any base.
Floating-point decimal values generally do not have an exact binary representation due to how the CPU represents floating point data. For this reason, you may experience a loss of precision, and some floating-point operations may produce unexpected results.
Specific to floating-point numbers, a floating-point operation is any mathematical operation (such as +, -, *, /) or assignment that involves floating-point numbers (as opposed to binary integer operations). Floating-point numbers have decimal points in them.
In C on my system:
printf("%.18f\n", result);
0.009000000000000001
In Python on my system:
print("%.18f" % result)
0.009000000000000001
C or Python like other languages limit the number of decimal digits by default with their print functions.
@ouah establishes that the languages are all behaving the same. My answer aims to explain why they appear different. The only two languages that have "different" output are C and Python.
Clearly, every language besides C and Python is just printing out the float value to as many decimal places as it can.
C is easy to explain. You use printf("%f", result)
, without specifying an explicit precision value. Per the C standard, the precision of the f
specifier defaults to 6. Thus, exactly six decimal places are printed out, which is what you see. As @ouah notes, setting the precision to 18 will yield the "expected" output. This is lossy: doubles that differ past the 7th decimal place will be printed out identically, and so the output of %f
cannot be relied on to exactly reconstruct the original float.
Python is a bit trickier. Python 3.1 introduced a new floating-point repr
algorithm, based on work by David Gay. The Python issue corresponding to the feature is here: http://bugs.python.org/issue1580. This feature was backported to Python 2.7 as well.
The intention of this new feature was to both reduce confusion over floating point (though that is dubiously useful), and more importantly to provide more human-readable, shorter representations of floating point numbers without affecting round-trip behaviour; that is, float(repr(x))
is always equal to x
, even if repr(x)
is shortened due to this algorithm. So, the algorithm manages to produce a shorter floating-point representation while remaining "lossless": win-win!
The official description says this much:
The new algorithm for repr(1.1) is smarter and returns '1.1'. Effectively, it searches all equivalent string representations (ones that get stored with the same underlying float value) and returns the shortest representation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With