Project

General

Profile

Actions

Feature #2969

closed

String#to_f が -h.hhh±pd を解釈できるように

Added by naruse (Yui NARUSE) about 14 years ago. Updated almost 13 years ago.

Status:
Closed
Assignee:
-
Target version:
-

Description

=begin
C99 の printf には a という指定子があります。

  aA          The argument is printed in style ‘[-h.hhh±pd]’ where there is
              one digit before the hexadecimal point and the number after
              is equal to the precision specification for the argument;
              when the precision is missing, enough digits are produced to
              convey the argument's exact double-precision floating-point
              representation.  The values ∞ and NaN are printed as ‘inf’
              and ‘nan’, respectively.

これを使うと、以下のような形で整形されます。
-0.0 #=> "-0x0p+0"
729.0/10 #=> "0x1.239999999999ap+6"
Math.log(3) #=> "0x1.193ea7aad030ap+0"
Math.exp(100) #=> "0x1.3494a9b171bf5p+144"

この形式の利点は、複雑な浮動小数点数を比較的少ない文字数で正確に表せることと、
仮数部が16進であるため丸めが起きていることを説明する際に便利な点が挙げられます。

で、この形式を使っているのですが、RubyのString#to_f で解釈してくれず悲しくなるので、
解釈できるようにしませんか。
パッチは以下の通りです。

diff --git a/util.c b/util.c
index 5ebc5f3..e361d51 100644
--- a/util.c
+++ b/util.c
@@ -2106,6 +2106,44 @@ ruby_strtod(const char *s00, char **se)
}
break2:
if (*s == '0') {

  •   if (s[1] == 'x') {
    
  •       static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
    
  •       s0 = ++s;
    
  •       adj = 0;
    
  •       while (*++s && (s1 = strchr(hexdigit, *s))) {
    
  •           adj *= 16;
    
  •           adj += (s1 - hexdigit) & 15;
    
  •       }
    
  •       if (*s == '.') {
    
  •           aadj = 1.;
    
  •           while (*++s && (s1 = strchr(hexdigit, *s))) {
    
  •               aadj /= 16;
    
  •               adj += aadj * ((s1 - hexdigit) & 15);
    
  •           }
    
  •       }
    
  •       if (*s != 'p') {
    
  •           s = s0;
    
  •           goto ret;
    
  •       }
    
  •       dsign = 0x2C - *++s; /* +: 2B, -: 2D */
    
  •       if (abs(dsign) != 1) {
    
  •           s = s0;
    
  •           goto ret;
    
  •       }
    
  •       for (nd = 0, s++; (c = *s) >= '0' && c <= '9'; s++) {
    
  •           nd *= 10;
    
  •           nd += c;
    
  •           nd -= '0';
    
  •       }
    
  •       dval(rv) = ldexp(adj, nd * dsign);
    
  •       goto ret;
    
  •   }
       nz0 = 1;
       while (*++s == '0') ;
       if (!*s)
    

diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index 64205f6..72d3242 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -1381,10 +1381,24 @@ class TestString < Test::Unit::TestCase
end

def test_to_f
  • assert_equal(0.0, S("0.0").to_f)
  • assert_equal(?0, S("0.0").to_f.to_s[0])
  • assert_equal(-0.0, S("-0.0").to_f)
  • assert_equal(?-, S("-0.0").to_f.to_s[0])
    assert_equal(344.3, S("344.3").to_f)
    assert_equal(5.9742e24, S("5.9742e24").to_f)
    assert_equal(98.6, S("98.6 degrees").to_f)
    assert_equal(0.0, S("degrees 100.0").to_f)
  • assert_equal(0.0, S("0x0p+0").to_f)
  • assert_equal(?0, S("0x0p+0").to_f.to_s[0])
  • assert_equal(-0.0, S("-0x0p+0").to_f)
  • assert_equal(?-, S("-0x0p+0").to_f.to_s[0])
  • assert_equal(1.0, S("0x1p+0").to_f)
  • assert_equal(?1, S("0x1p+0").to_f.to_s[0])
  • assert_equal(1024.0, S("0x1p+10").to_f)
  • assert_equal(0.0009765625, S("0x1p-10").to_f)
  • assert_equal(2.6881171418161356e+43, S("0x1.3494a9b171bf5p+144").to_f)
  • assert_equal(-3.720075976020836e-44, S("-0x1.a8c1f14e2af5dp-145").to_f)
    end
def test_to_i

=end

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0