5 ms·
Fun fact: floor(x + 0.5) rounds 0.49999997 to 1.0 (this is 32 bit floats, the same principle applies to 64). Most libraries have slower than ideal round convers
by raphlinus 7y ago
Fun fact: floor(x + 0.5) rounds 0.49999997 to 1.0 (this is 32 bit floats, the same principle applies to 64). Most libraries have slower than ideal round conversion because of historical dross; modern chips have a very fast SIMD round instruction but its behavior doesn't exactly match libc round. See https://github.com/rust-lang/rust/issues/55107 https://github.com/rust-lang/rust/issues/55107 for a deeper discussion.
- dwheeler 7y agoI just tried this on Python3 on a 64-bit x86 system: import math x = 0.49999999999999994 print(x-0.5) print(math.floor(x+0.5)) I got these printouts: -5.551115123125783e-17 1 So yes, something less than 1/2, with 1/2 added to it, has a floor of 1 in floating point math. Yet another reminder that floating point calculations are approximations, and not exact.
- deleted 7y ago[deleted]
- e12e 7y agoIn Julia it's easy to see the difference between promoting to full number tower and sticking to 64 floats (ed: note difference in result 0 vs 1): julia> using Benchmarktools julia> @btime floor(0.49999999999999997+0.5) 0.027 ns (0 allocations: 0 bytes) 1.0 julia> @btime floor(0.49999999999999997+BigFloat(0.5)) 280.594 ns (6 allocations: 336 bytes) 0.0 julia> @code_native floor(0.49999999999999997+BigFloat(0.5)) .text ; ┌ @ floatfuncs.jl:152 within `floor' subq $24, %rsp movq %rsi, 16(%rsp) movq (%rsi), %rax ; │┌ @ floatfuncs.jl:152 within `#floor#543' movq %rax, (%rsp) movabsq $jl_system_image_data, %rax movq %rax, 8(%rsp) movabsq $japi1_round_16005, %rax movabsq $jl_system_image_data, %rdi movq %rsp, %rsi movl $2, %edx callq *%rax ; │└ addq $24, %rsp retq nopw %cs:(%rax,%rax) ; └ julia> @code_native floor(0.49999999999999997+0.5) .text ; ┌ @ floatfuncs.jl:152 within `floor' ; │┌ @ floatfuncs.jl:152 within `#floor#543' ; ││┌ @ floatfuncs.jl:152 within `round' vroundsd $9, %xmm0, %xmm0, %xmm0 ; │└└ retq nopw (%rax,%rax) ; └
- masklinn 7y ago> Yet another reminder that floating point calculations are approximations, and not exact. floating-point calculations are absolutely exact. What's not is conversions between decimals and floating-point.
- murkle 7y ago> floating-point calculations are absolutely exact Are you sure about that? What about 1.00000000000001^2 (using eg 64 bit double)?
- lifthrasiir 7y agoMaybe the parent wanted to say that the result is detetministic and not far too off from the true value (in fact, as accurate as possible given the format). In the other words FP is exact but abides by a slight different calculation rule involving rounding.
- dwheeler 7y agoFloating point is usually deterministic, but from a math point of view it is inexact (in most cases it only approximates the exact answer). In many cases that is fine, which is why it is used, but it is important to remember that.
- edflsafoiewq 7y agoTheir not being exact is why 0.49999997 + 0.5 = 1. There isn't enough precision in the range just below 1.0 to represent the number 0.99999997.
- jacobolus 7y agoIf the number is positive you can substitute floor(x - 0.5) + 1 Or just explicitly check for 0.5 - 1ulp as a special corner case.
- analog31 7y agoGood call. I usually only use this conversion when the input is approximate to begin with, e.g., feeding a floating point "signal" to a DAC, or computing the contents of a lookup table to be coded into an arduino. To put it another way, I can live with some uncertainty as to the precise threshold going from one output value to the next.