From: Robert Klemme Date: 2011-12-15T17:14:13+09:00 Subject: Re: round float to integer if whole number On Wed, Dec 14, 2011 at 11:21 PM, Ronnie Aa wrote: > Gunther Diemant wrote in post #1036785: >> Possible tests: >> ff.floor == ff >> ff % 1 == 0 >> >> If x is always an integer i would use the mod operator ( x % w == 0 >> ==> x/w integer) >> >> 2011/12/14 Ronnie Aa : > > thanxs Gunther! That test does not work reliably: irb(main):006:0> x = 1.0 => 1.0 irb(main):007:0> x.class => Float irb(main):008:0> 20.times do |i| irb(main):009:1* y = x + (10.0 ** -i) irb(main):010:1> printf "%4d %20.16f %s\n", i, y, y == y.floor irb(main):011:1> end 0 2.0000000000000000 true 1 1.1000000000000001 false 2 1.0100000000000000 false 3 1.0009999999999999 false 4 1.0001000000000000 false 5 1.0000100000000001 false 6 1.0000009999999999 false 7 1.0000001000000001 false 8 1.0000000099999999 false 9 1.0000000010000001 false 10 1.0000000001000000 false 11 1.0000000000100000 false 12 1.0000000000010001 false 13 1.0000000000000999 false 14 1.0000000000000100 false 15 1.0000000000000011 false 16 1.0000000000000000 true 17 1.0000000000000000 true 18 1.0000000000000000 true 19 1.0000000000000000 true => 20 irb(main):024:0* x = BigDecimal.new "1.0" => # irb(main):025:0> 20.times do |i| irb(main):026:1* y = x + (BigDecimal.new("10.0") ** -i) irb(main):027:1> printf "%4d %30.24f %s\n", i, y, y == y.floor irb(main):028:1> end 0 2.000000000000000000000000 true 1 1.100000000000000088817842 false 2 1.010000000000000008881784 false 3 1.000999999999999889865876 false 4 1.000099999999999988986588 false 5 1.000010000000000065512040 false 6 1.000000999999999917733362 false 7 1.000000100000000058386718 false 8 1.000000009999999939225290 false 9 1.000000001000000082740371 false 10 1.000000000100000008274037 false 11 1.000000000010000000827404 false 12 1.000000000001000088900582 false 13 1.000000000000099920072216 false 14 1.000000000000009992007222 false 15 1.000000000000001110223025 false 16 1.000000000000000000000000 false 17 1.000000000000000000000000 false 18 1.000000000000000000000000 false 19 1.000000000000000000000000 false => 20 It is better to define "equality" differently for floating point numbers. There are a few common approaches: 1. Define a maximum difference that you accept, e.g. irb(main):029:0> x = 1.0 => 1.0 irb(main):030:0> 20.times do |i| irb(main):031:1* y = x + (10.0 ** -i) irb(main):032:1> printf "%4d %30.24f %s\n", i, y, (y - y.floor).abs < 1e-5 irb(main):033:1> end 0 2.000000000000000000000000 true 1 1.100000000000000088817842 false 2 1.010000000000000008881784 false 3 1.000999999999999889865876 false 4 1.000099999999999988986588 false 5 1.000010000000000065512040 false 6 1.000000999999999917733362 true 7 1.000000100000000058386718 true 8 1.000000009999999939225290 true 9 1.000000001000000082740371 true 10 1.000000000100000008274037 true 11 1.000000000010000000827404 true 12 1.000000000001000088900582 true 13 1.000000000000099920072216 true 14 1.000000000000009992007222 true 15 1.000000000000001110223025 true 16 1.000000000000000000000000 true 17 1.000000000000000000000000 true 18 1.000000000000000000000000 true 19 1.000000000000000000000000 true => 20 2. Define a maximum delta for the factor to 1 irb(main):034:0> 20.times do |i| irb(main):035:1* y = x + (10.0 ** -i) irb(main):036:1> printf "%4d %30.24f %s\n", i, y, ((y / y.floor) - 1).abs < 1e-5 irb(main):037:1> end 0 2.000000000000000000000000 true 1 1.100000000000000088817842 false 2 1.010000000000000008881784 false 3 1.000999999999999889865876 false 4 1.000099999999999988986588 false 5 1.000010000000000065512040 false 6 1.000000999999999917733362 true 7 1.000000100000000058386718 true 8 1.000000009999999939225290 true 9 1.000000001000000082740371 true 10 1.000000000100000008274037 true 11 1.000000000010000000827404 true 12 1.000000000001000088900582 true 13 1.000000000000099920072216 true 14 1.000000000000009992007222 true 15 1.000000000000001110223025 true 16 1.000000000000000000000000 true 17 1.000000000000000000000000 true 18 1.000000000000000000000000 true 19 1.000000000000000000000000 true => 20 Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/