core: implement Float::to_precision in C without callbacks
authorAlexis Laferrière <alexis.laf@xymus.net>
Tue, 3 Oct 2017 14:53:59 +0000 (10:53 -0400)
committerAlexis Laferrière <alexis.laf@xymus.net>
Tue, 3 Oct 2017 18:45:38 +0000 (14:45 -0400)
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 <alexis.laf@xymus.net>

lib/core/text/abstract_text.nit
tests/sav/fibonacci_word.res
tests/sav/montecarlo.res
tests/sav/perlin_noise.res
tests/sav/test_attr_easy.res
tests/sav/test_math.res

index a09843d..3f37a81 100644 (file)
@@ -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
index 38a9498..dfb2522 100644 (file)
@@ -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      ...
index 58ad327..82286d6 100644 (file)
@@ -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
index 58a5cf2..75ca824 100644 (file)
@@ -1 +1 @@
-0.13691995878400010
+0.13691995878400012
index 9357190..84b6677 100644 (file)
@@ -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
index 4ea9f3c..840f390 100644 (file)
@@ -1,7 +1,7 @@
 3.142
 -1.0
 0.0
-0.0
+-0.0
 0.785
 0.0
 1.571