From 6af385b22805cc2e8cee5c0a5f3506361afbe961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20L=C3=A5ng?= Date: Fri, 23 Oct 2015 15:27:22 +0200 Subject: 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. --- lib/hipe/rtl/hipe_rtl_binary_construct.erl | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'lib/hipe') 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). -- cgit v1.2.3