From: Alexis Laferrière Date: Tue, 3 Oct 2017 14:53:59 +0000 (-0400) Subject: core: implement Float::to_precision in C without callbacks X-Git-Url: http://nitlanguage.org core: implement Float::to_precision in C without callbacks Fix int overflows in Float::to_precision with a high float value or a high precision. The native implementation was removed by 9cb09ccf to support the interpreter, which, at the time, did not support the FFI. Since then, we added support for thhe FFI in the interpreter. Signed-off-by: Alexis Laferrière --- diff --git a/lib/core/text/abstract_text.nit b/lib/core/text/abstract_text.nit index a09843d..3f37a81 100644 --- a/lib/core/text/abstract_text.nit +++ b/lib/core/text/abstract_text.nit @@ -1915,35 +1915,23 @@ redef class Float return "-inf" end - if decimals == 0 then return self.to_i.to_s - var f = self - for i in [0..decimals[ do f = f * 10.0 - if self > 0.0 then - f = f + 0.5 - else - f = f - 0.5 - end - var i = f.to_i - if i == 0 then return "0." + "0"*decimals - - # Prepare both parts of the float, before and after the "." - var s = i.abs.to_s - var sl = s.length - var p1 - var p2 - if sl > decimals then - # Has something before the "." - p1 = s.substring(0, sl-decimals) - p2 = s.substring(sl-decimals, decimals) - else - p1 = "0" - p2 = "0"*(decimals-sl) + s - end + var size = to_precision_size(decimals) + var cstr = new CString(size+1) + to_precision_fill(decimals, size+1, cstr) + return cstr.to_s_unsafe(byte_length=size, copy=false) + end - if i < 0 then p1 = "-" + p1 + # Required string length to hold `self` with `nb` decimals + # + # The length does not include the terminating null byte. + private fun to_precision_size(nb: Int): Int `{ + return snprintf(NULL, 0, "%.*f", (int)nb, self); + `} - return p1 + "." + p2 - end + # Fill `cstr` with `self` and `nb` decimals + private fun to_precision_fill(nb, size: Int, cstr: CString) `{ + snprintf(cstr, size, "%.*f", (int)nb, self); + `} end redef class Char diff --git a/tests/sav/fibonacci_word.res b/tests/sav/fibonacci_word.res index 38a9498..dfb2522 100644 --- a/tests/sav/fibonacci_word.res +++ b/tests/sav/fibonacci_word.res @@ -1,37 +1,37 @@ 1 1 0.0000000000000000 1 2 1 0.0000000000000000 0 3 2 1.0000000000000000 01 -4 3 0.9182958340544894 010 +4 3 0.9182958340544896 010 5 5 0.9709505944546686 01001 -6 8 0.9544340029249650 01001010 +6 8 0.9544340029249649 01001010 7 13 0.9612366047228760 0100101001001 -8 21 0.9587118829771316 010010100100101001010 -9 34 0.9596868937742170 0100101001001010010100100101001001 -10 55 0.9593160320543778 ... +8 21 0.9587118829771318 010010100100101001010 +9 34 0.9596868937742169 0100101001001010010100100101001001 +10 55 0.9593160320543777 ... 11 89 0.9594579158386696 ... -12 144 0.9594037542210228 ... -13 233 0.9594244469559864 ... -14 377 0.9594165437404406 ... -15 610 0.9594195626031440 ... -16 987 0.9594184095152248 ... -17 1597 0.9594188499578102 ... -18 2584 0.9594186817240320 ... +12 144 0.9594037542210230 ... +13 233 0.9594244469559867 ... +14 377 0.9594165437404407 ... +15 610 0.9594195626031441 ... +16 987 0.9594184095152245 ... +17 1597 0.9594188499578099 ... +18 2584 0.9594186817240321 ... 19 4181 0.9594187459836638 ... -20 6765 0.9594187214386752 ... -21 10946 0.9594187308140276 ... -22 17711 0.9594187272329618 ... -23 28657 0.9594187286008076 ... -24 46368 0.9594187280783368 ... -25 75025 0.9594187282779028 ... -26 121393 0.9594187282016752 ... -27 196418 0.9594187282307916 ... +20 6765 0.9594187214386756 ... +21 10946 0.9594187308140278 ... +22 17711 0.9594187272329620 ... +23 28657 0.9594187286008073 ... +24 46368 0.9594187280783371 ... +25 75025 0.9594187282779029 ... +26 121393 0.9594187282016755 ... +27 196418 0.9594187282307918 ... 28 317811 0.9594187282196702 ... -29 514229 0.9594187282239182 ... -30 832040 0.9594187282222962 ... +29 514229 0.9594187282239184 ... +30 832040 0.9594187282222959 ... 31 1346269 0.9594187282229156 ... -32 2178309 0.9594187282226794 ... -33 3524578 0.9594187282227690 ... -34 5702887 0.9594187282227344 ... -35 9227465 0.9594187282227478 ... -36 14930352 0.9594187282227430 ... +32 2178309 0.9594187282226789 ... +33 3524578 0.9594187282227691 ... +34 5702887 0.9594187282227347 ... +35 9227465 0.9594187282227479 ... +36 14930352 0.9594187282227429 ... 37 24157817 0.9594187282227448 ... diff --git a/tests/sav/montecarlo.res b/tests/sav/montecarlo.res index 58ad327..82286d6 100644 --- a/tests/sav/montecarlo.res +++ b/tests/sav/montecarlo.res @@ -7,5 +7,5 @@ i=32 h=19 p=2.375000 i=64 h=45 p=2.812500 i=128 h=95 p=2.968750 i=256 h=197 p=3.078125 -i=512 h=385 p=3.007813 +i=512 h=385 p=3.007812 i=1000 h=765 p=3.060000 diff --git a/tests/sav/perlin_noise.res b/tests/sav/perlin_noise.res index 58a5cf2..75ca824 100644 --- a/tests/sav/perlin_noise.res +++ b/tests/sav/perlin_noise.res @@ -1 +1 @@ -0.13691995878400010 +0.13691995878400012 diff --git a/tests/sav/test_attr_easy.res b/tests/sav/test_attr_easy.res index 9357190..84b6677 100644 --- a/tests/sav/test_attr_easy.res +++ b/tests/sav/test_attr_easy.res @@ -5,7 +5,7 @@ test_attr_easy.nit:19,43--53: Warning: expression is already a `Float`. test_attr_easy.nit:20,5--16: Warning: expression is already a `String`. test_attr_easy.nit:20,20--26: Warning: expression is already a `B`. test_attr_easy.nit:20,44--63: Warning: expression is already a `HashMap[Int, B]`. -true false 12345 1.235 asdf true +true false 12345 1.234 asdf true an instance of B true true true true true true true true diff --git a/tests/sav/test_math.res b/tests/sav/test_math.res index 4ea9f3c..840f390 100644 --- a/tests/sav/test_math.res +++ b/tests/sav/test_math.res @@ -1,7 +1,7 @@ 3.142 -1.0 0.0 -0.0 +-0.0 0.785 0.0 1.571