int((0.1+0.7)*10) = 7 in several languages. How to

2019-01-05 03:01发布

Recently I came across a bug/feature in several languages. I have a very basic knowledge about how it's caused (and I'd like some detailed explanation), but when I think of all the bugs I must have made over the years, the question is how can I determine "Hey, this might cause a riddiculous bug, I'd better use arbitrary precision functions", what other languages do have this bug (and those who don't, why). Also, why 0.1+0.7 does this and i.e. 0.1+0.3 doesn't, are there any other well-known examples?

PHP

//the first one actually doesn't make any sense to me,
//why 7 after typecast if it's represented internally as 8?
debug_zval_dump((0.1+0.7)*10); //double(8) refcount(1)
debug_zval_dump((int)((0.1+0.7)*10)); //long(7) refcount(1)
debug_zval_dump((float)((0.1+0.7)*10)); //double(8) refcount(1)

Python:

>>> ((0.1+0.7)*10)
7.9999999999999991
>>> int((0.1+0.7)*10)
7

Javascript:

alert((0.1+0.7)*10); //7.999999999999999
alert(parseInt((0.7+0.1)*10)); //7

Ruby:

>> ((0.1+0.7)*10).to_i                                                  
=> 7                                                                    
>>((0.1+0.7)*10)                                                       
=> 7.999999999999999                                                    

7条回答
We Are One
3楼-- · 2019-01-05 03:12
仙女界的扛把子
4楼-- · 2019-01-05 03:12

This is a known problem that has to do with floating point representation, from which you can find more information here:

http://en.wikipedia.org/wiki/IEEE_754-2008

The specific problem is that 7.9 will be directly converted (trunc) to 7 while transforming it to an int. In Python you can solve this with:

int( round(((0.1+0.7)*10)) )

... and similarly in other languages.

But yes, this can be a problem in many situations. Floating point numbers are not reliable enough for payroll programs, for example.

Maybe others can give you other hints. Hpe this helps, anywway.

查看更多
Ridiculous、
5楼-- · 2019-01-05 03:16

Use the decimal module:

>>> int((decimal.Decimal('0.1')+decimal.Decimal('0.7'))*10)
8
查看更多
孤傲高冷的网名
6楼-- · 2019-01-05 03:23

It's not a language issue. It's general issue with float point arithmetic.

查看更多
乱世女痞
7楼-- · 2019-01-05 03:27

The floating point representation of numbers is not exact.

In Python, int truncates floats towards zero to the nearest integer. (int) in PHP, parseInt in Javascript, and to_i in Ruby do the same thing.

This is not a bug; it's just how these functions work.

For example, from the docs for Python's int:

Conversion of floating point numbers to integers truncates (towards zero).

查看更多
登录 后发表回答