aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMagnus Lång <[email protected]>2015-10-23 15:27:22 +0200
committerMagnus Lång <[email protected]>2015-11-27 18:18:37 +0100
commit6af385b22805cc2e8cee5c0a5f3506361afbe961 (patch)
tree2099f8ccea46f21ed09886eef4abb582455e0de1
parenta838b671ef9cc7582f0768778a0447df614b71dd (diff)
downloadotp-6af385b22805cc2e8cee5c0a5f3506361afbe961.tar.gz
otp-6af385b22805cc2e8cee5c0a5f3506361afbe961.tar.bz2
otp-6af385b22805cc2e8cee5c0a5f3506361afbe961.zip
Fix hipe_rtl_binary_construct:floorlog2/1
Relying on double-precision floating-point arithmetic to compute the log2 of an integer up to 64 bits long leads to rounding errors.
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_construct.erl14
1 files changed, 13 insertions, 1 deletions
diff --git a/lib/hipe/rtl/hipe_rtl_binary_construct.erl b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
index 692bad7d96..d01625b4f9 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_construct.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
@@ -1330,7 +1330,19 @@ number2list(X, Acc) ->
number2list(X-(1 bsl F), [F|Acc]).
floorlog2(X) ->
- round(math:log(X)/math:log(2)-0.5).
+ %% Double-precision floats do not have enough precision to make floorlog2
+ %% exact for integers larger than 2^47.
+ Approx = round(math:log(X)/math:log(2)-0.5),
+ floorlog2_refine(X, Approx).
+
+floorlog2_refine(X, Approx) ->
+ if (1 bsl Approx) > X ->
+ floorlog2_refine(X, Approx - 1);
+ (1 bsl (Approx+1)) > X ->
+ Approx;
+ true ->
+ floorlog2_refine(X, Approx + 1)
+ end.
set_high(X) ->
set_high(X, 0).