diff options
author | Magnus Lång <[email protected]> | 2015-10-23 15:27:22 +0200 |
---|---|---|
committer | Magnus Lång <[email protected]> | 2015-11-27 18:18:37 +0100 |
commit | 6af385b22805cc2e8cee5c0a5f3506361afbe961 (patch) | |
tree | 2099f8ccea46f21ed09886eef4abb582455e0de1 | |
parent | a838b671ef9cc7582f0768778a0447df614b71dd (diff) | |
download | otp-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.erl | 14 |
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). |