5.000...007.to_s => "5"

irb(main):001:0> 5.00000000000007.to_s
=> “5.00000000000007”

irb(main):002:0> 5.000000000000007.to_s
=> “5.00000000000001”

irb(main):003:0> 5.0000000000000007.to_s
=> “5”

irb(main):004:0> 5.00000000000000007.to_s
=> “5.0”

Note the weirdness in the third item, as reported by ‘quix’ on the
#ruby-lang IRC channel.

(The issue is not the lack of float precision…that’s gotta give out
at some point. The issue is the “5” vs. “5.0” discrepancy.)

···


(-, /\ / / //

Try this patch:

— numeric.c.orig 2004-04-21 04:31:04.000000000 +0300
+++ numeric.c 2004-04-21 04:31:08.000000000 +0300
@@ -490,10 +490,10 @@
VALUE flt;
{
char buf[32];

  • char *fmt = “%.15g”;
  • char *fmt = “%.15f”;
    double value = RFLOAT(flt)->value;
    double avalue, d1, d2;
···

On Thu, Apr 22, 2004 at 02:48:18AM +0900, Gavin Kistner wrote:

irb(main):001:0> 5.00000000000007.to_s
=> “5.00000000000007”

irb(main):002:0> 5.000000000000007.to_s
=> “5.00000000000001”

irb(main):003:0> 5.0000000000000007.to_s
=> “5”

irb(main):004:0> 5.00000000000000007.to_s
=> “5.0”

Note the weirdness in the third item, as reported by ‘quix’ on the
#ruby-lang IRC channel.

(The issue is not the lack of float precision…that’s gotta give out
at some point. The issue is the “5” vs. “5.0” discrepancy.)

  • if (isinf(value))
    return rb_str_new2(value < 0 ? “-Infinity” : “Infinity”);
    else if(isnan(value))


University of Athens I bet the human brain
Physics Department is a kludge --Marvin Minsky

Hi,

At Thu, 22 Apr 2004 02:48:18 +0900,
Gavin Kistner wrote in [ruby-talk:97891]:

(The issue is not the lack of float precision…that’s gotta give out
at some point. The issue is the “5” vs. “5.0” discrepancy.)

Seems the issue about the boundary between “e” and “f”.

Index: numeric.c

···

===================================================================
RCS file: /cvs/ruby/src/ruby/numeric.c,v
retrieving revision 1.106
diff -u -2 -p -r1.106 numeric.c
— numeric.c 14 Apr 2004 04:06:25 -0000 1.106
+++ numeric.c 21 Apr 2004 18:54:14 -0000
@@ -517,5 +517,5 @@ flo_to_s(flt)
else fmt = “%.16e”;
}

  • else if ((d1 = modf(value, &d2)) == 0) {
  • else if (fabs(modf(avalue, &d2)) <= 1.0e-15) {
    fmt = “%.1f”;
    }


Nobu Nakada

Still, default fmt in flo_to_s() is iniatialized to ‘g’ (which
cuts trailing decimal points).

Regards,

···

On Thu, Apr 22, 2004 at 03:59:54AM +0900, nobu.nokada@softhome.net wrote:

Hi,

At Thu, 22 Apr 2004 02:48:18 +0900,
Gavin Kistner wrote in [ruby-talk:97891]:

(The issue is not the lack of float precision…that’s gotta give out
at some point. The issue is the “5” vs. “5.0” discrepancy.)

Seems the issue about the boundary between “e” and “f”.


University of Athens I bet the human brain
Physics Department is a kludge --Marvin Minsky

This fixes 1.000…7 but does not fix two other cases I didn’t mention,

arda:~/cur/ruby> ./ruby -e ‘puts 1.00000000000004.to_s’
1.00000000000004
arda:~/cur/ruby> ./ruby -e ‘puts 1.000000000000004.to_s’
1
arda:~/cur/ruby> ./ruby -e ‘puts 1.0000000000000004.to_s’
1.0
arda:~/cur/ruby> ./ruby -e ‘puts 1.99999999999999.to_s’
1.99999999999999
arda:~/cur/ruby> ./ruby -e ‘puts 1.999999999999999.to_s’
2
arda:~/cur/ruby> ./ruby -e ‘puts 1.9999999999999999.to_s’
2.0

···

nobu.nokada@softhome.net wrote:

Hi,

At Thu, 22 Apr 2004 02:48:18 +0900,
Gavin Kistner wrote in [ruby-talk:97891]:

(The issue is not the lack of float precision…that’s gotta give out
at some point. The issue is the “5” vs. “5.0” discrepancy.)

Seems the issue about the boundary between “e” and “f”.


Do you Yahoo!?
Yahoo! Photos: High-quality 4x6 digital prints for 25¢
http://photos.yahoo.com/ph/print_splash

Hi,

···

In message "Re: 5.000…007.to_s => “5"” on 04/04/22, Elias Athanasopoulos elathan@phys.uoa.gr writes:

Seems the issue about the boundary between “e” and “f”.

Still, default fmt in flo_to_s() is iniatialized to ‘g’ (which
cuts trailing decimal points).

It needs to be ‘g’ for scientific notation for some very big (or very
small) numbers. By the way, 1.0e-15 epsilon is not sufficient for
numbers such as 5.0000000000000046. I propose 5.0e-15.

						matz.

Hi,

At Thu, 22 Apr 2004 04:36:05 +0900,
Jeff Mitchell wrote in [ruby-talk:97924]:

This fixes 1.000…7 but does not fix two other cases I didn’t mention,

arda:~/cur/ruby> ./ruby -e ‘puts 1.00000000000004.to_s’
1.00000000000004
arda:~/cur/ruby> ./ruby -e ‘puts 1.000000000000004.to_s’
1
arda:~/cur/ruby> ./ruby -e ‘puts 1.0000000000000004.to_s’
1.0
arda:~/cur/ruby> ./ruby -e ‘puts 1.99999999999999.to_s’
1.99999999999999
arda:~/cur/ruby> ./ruby -e ‘puts 1.999999999999999.to_s’
2
arda:~/cur/ruby> ./ruby -e ‘puts 1.9999999999999999.to_s’
2.0

Hmmm…, I didn’t consider about upper boundary.

Index: numeric.c

···

===================================================================
RCS file: /cvs/ruby/src/ruby/numeric.c,v
retrieving revision 1.106
diff -u -2 -p -r1.106 numeric.c
— numeric.c 14 Apr 2004 04:06:25 -0000 1.106
+++ numeric.c 22 Apr 2004 01:00:45 -0000
@@ -517,5 +517,5 @@ flo_to_s(flt)
else fmt = “%.16e”;
}

  • else if ((d1 = modf(value, &d2)) == 0) {
  • else if ((d1 = modf(avalue, &d2)) <= 5.0e-15 || (1.0 - d1) <= 5.0e-15) {
    fmt = “%.1f”;
    }


Nobu Nakada

Still more to come :slight_smile:

Here’s a MIME-64 containing 8 marshalled Floats:
BAhmGjI0LjAwMDAwMDAwMDAwMDAwNAAAAQQIZhoyNy45OTk5OTk5OTk5OTk5OTYA//8ECGYaNDQu
MDAwMDAwMDAwMDAwMDA3AAABBAhmGjQ1Ljk5OTk5OTk5OTk5OTk5MwD//wQIZho0OC4wMDAwMDAw
MDAwMDAwMDcAAAEECGYaNTEuOTk5OTk5OTk5OTk5OTkzAP//BAhmGjU0LjAwMDAwMDAwMDAwMDAw
NwAAAQQIZho4My45OTk5OTk5OTk5OTk5ODYA//8=

File.open(ARGV.shift) { |file|
begin
while a = Marshal.load(file)
puts “#{a.class} #{a}”
end
rescue EOFError
end
}

Output should be:
Float 24
Float 28
Float 44
Float 46
Float 48
Float 52
Float 54
Float 84

Oddly enough, with your patch the first two floats are fixed,
showing 24.0 and 28.0 (which is entirely a coincidence; this
list didn’t exist when I came up with the original numbers).
The rest are as shown.

I’d have used ruby’s mime-types but I couldn’t get it to compile :confused:

···

nobu.nokada@softhome.net wrote:

Hi,

At Thu, 22 Apr 2004 04:36:05 +0900,
Jeff Mitchell wrote in [ruby-talk:97924]:

This fixes 1.000…7 but does not fix two other cases I didn’t mention,

arda:~/cur/ruby> ./ruby -e ‘puts 1.00000000000004.to_s’
1.00000000000004
arda:~/cur/ruby> ./ruby -e ‘puts 1.000000000000004.to_s’
1
arda:~/cur/ruby> ./ruby -e ‘puts 1.0000000000000004.to_s’
1.0
arda:~/cur/ruby> ./ruby -e ‘puts 1.99999999999999.to_s’
1.99999999999999
arda:~/cur/ruby> ./ruby -e ‘puts 1.999999999999999.to_s’
2
arda:~/cur/ruby> ./ruby -e ‘puts 1.9999999999999999.to_s’
2.0

Hmmm…, I didn’t consider about upper boundary.


Do you Yahoo!?
Yahoo! Photos: High-quality 4x6 digital prints for 25¢
http://photos.yahoo.com/ph/print_splash

Hi,

At Thu, 22 Apr 2004 11:33:44 +0900,
Jeff Mitchell wrote in [ruby-talk:97988]:

Oddly enough, with your patch the first two floats are fixed,
showing 24.0 and 28.0 (which is entirely a coincidence; this
list didn’t exist when I came up with the original numbers).
The rest are as shown.

$ cat f.rb
#! /usr/bin/ruby
require ‘hexfloat’ # http://nokada.jin.gr.jp/ruby/hexfloat.rb
require ‘stringio’

def show(a)
d = a%1
printf “%s %-20s %-20s %-20s %-20s\n”, a.class, a.to_s, a.hex, d.hex, (1.0-d).hex
end

[5.00000000000007, 5.000000000000007, 5.0000000000000007, 5.00000000000000007,
1.00000000000004, 1.000000000000004, 1.0000000000000004,
1.99999999999999, 1.999999999999999, 1.9999999999999999].each(&method(:show))

StringIO.open(*DATA.read.unpack(“m”)) do |file|
begin
while a = Marshal.load(file)
show(a)
end
rescue EOFError
end
end

END
BAhmGjI0LjAwMDAwMDAwMDAwMDAwNAAAAQQIZhoyNy45OTk5OTk5OTk5OTk5OTYA//8ECGYaNDQu
MDAwMDAwMDAwMDAwMDA3AAABBAhmGjQ1Ljk5OTk5OTk5OTk5OTk5MwD//wQIZho0OC4wMDAwMDAw
MDAwMDAwMDcAAAEECGYaNTEuOTk5OTk5OTk5OTk5OTkzAP//BAhmGjU0LjAwMDAwMDAwMDAwMDAw
NwAAAQQIZho4My45OTk5OTk5OTk5OTk5ODYA//8=

$ ./ruby f.rb
Float 5.00000000000007 0x5.000000000013c 0x1.3cp-44 0xf.fffffffffec4p-4
Float 5.00000000000001 0x5.000000000002 0x2.0p-48 0xf.ffffffffffep-4
Float 5.0 0x5.0000000000004 0x4.0p-52 0xf.fffffffffffcp-4
Float 5.0 0x5.0 0x0.0p-4 0x1.0
Float 1.00000000000004 0x1.00000000000b4 0xb.4p-48 0xf.ffffffffff4cp-4
Float 1.0 0x1.0000000000012 0x1.2p-48 0xf.ffffffffffeep-4
Float 1.0 0x1.0000000000002 0x2.0p-52 0xf.fffffffffffep-4
Float 1.99999999999999 0x1.fffffffffffd3 0xf.ffffffffffd3p-4 0x2.dp-48
Float 2.0 0x1.ffffffffffffb 0xf.fffffffffffbp-4 0x5.0p-52
Float 2.0 0x2.0 0x0.0p-4 0x1.0
Float 24.0 0x1.8000000000001p+4 0x1.0p-48 0xf.fffffffffffp-4
Float 28.0 0x1.bffffffffffffp+4 0xf.fffffffffffp-4 0x1.0p-48
Float 44.0 0x2.c000000000002p+4 0x2.0p-48 0xf.ffffffffffep-4
Float 46.0 0x2.dfffffffffffep+4 0xf.ffffffffffep-4 0x2.0p-48
Float 48.0 0x3.0000000000002p+4 0x2.0p-48 0xf.ffffffffffep-4
Float 52.0 0x3.3fffffffffffep+4 0xf.ffffffffffep-4 0x2.0p-48
Float 54.0 0x3.6000000000002p+4 0x2.0p-48 0xf.ffffffffffep-4
Float 84.0 0x5.3fffffffffffcp+4 0xf.ffffffffffcp-4 0x4.0p-48

The range to be .f format is affected by also its precision.
This might be rather realistic.

Index: numeric.c

···

===================================================================
RCS file: /cvs/ruby/src/ruby/numeric.c,v
retrieving revision 1.106
diff -u -2 -p -r1.106 numeric.c
— numeric.c 14 Apr 2004 04:06:25 -0000 1.106
+++ numeric.c 22 Apr 2004 04:34:22 -0000
@@ -517,8 +517,6 @@ flo_to_s(flt)
else fmt = “%.16e”;
}

  • else if ((d1 = modf(value, &d2)) == 0) {
  • fmt = “%.1f”;
  • }
    sprintf(buf, fmt, value);
  • if (!strchr(buf, ‘.’)) strcat(buf, “.0”);

    return rb_str_new2(buf);


Nobu Nakada

Sorry for late posting. Does this patch solve your problem?

  • numeric.c(flo_to_s): use DBL_DIG to show only significant digits.

Index: numeric.c

···

===================================================================
RCS file: /ruby/ruby/numeric.c,v
retrieving revision 1.107
diff -u -w -b -p -r1.107 numeric.c
— numeric.c 7 May 2004 08:44:15 -0000 1.107
+++ numeric.c 10 May 2004 04:00:45 -0000
@@ -489,10 +489,9 @@ static VALUE
flo_to_s(flt)
VALUE flt;
{

  • char buf[32];
  • char *fmt = “%.15f”;
  • char fmt[sizeof(int)*3+10], buf[sizeof(double)*3+sizeof(int)*3+20];
    double value = RFLOAT(flt)->value;
  • double avalue, d1, d2;
  • int exp;
    char *p, *e;

    if (isinf(value))
    @@ -500,13 +499,25 @@ flo_to_s(flt)
    else if(isnan(value))
    return rb_str_new2(“NaN”);

  • avalue = fabs(value);
  • if (avalue < 1.0e-7 || avalue >= 1.0e15) {
  • fmt = “%.16e”;
  • }
  • sprintf(fmt, “%%.%de”, DBL_DIG - 1);
    sprintf(buf, fmt, value);
  • if (!(e = strchr(buf, ‘e’))) {
  • e = buf + strlen(buf);
  • e = strchr(buf, ‘e’);
  • exp = atoi(e+1);
  • if (-7 <= exp && exp < DBL_DIG - 1) {
  • char *d = strchr(buf, ‘.’);
  • if (exp > 0) {
  •   memmove(d, d+1, exp);
    
  •   d[exp] = '.';
    
  • }
  • if (exp < 0) { /* needs room in `buf’ for shifting (currently 7) */
  •   int n = -exp;
    
  •   d[0] = d[-1];
    
  •   memmove(d+n, d, strlen(d)+1);
    
  •   e += n;
    
  •   memset(buf, '0', n+1);
    
  •   buf[1] = '.';
    
  • }
  • e = ‘\0’;
    }
    p = e;
    while (
    –p==‘0’)

$ cat f.rb
[snip]

This is nice… I wasn’t aware that Ruby has a ‘END’ tag.

ruby d.rb
before
middle
after
expand -2 d.rb
puts “before”
eval DATA.read
puts “after”
END
puts “middle”

Are there other sweet things like this?

···

nobu.nokada@softhome.net wrote:


Simon Strandgaard

This thread seems dead though…

There was bug in my patch. Correct one is posted at [ruby-dev:23507]

Float(-0.1).to_s #=> “0.11” (should be “-0.1”)

Thank you.

“Simon Strandgaard” neoneye@adslhome.dk schrieb im Newsbeitrag
news:20040422110932.0a700297.neoneye@adslhome.dk…

···

nobu.nokada@softhome.net wrote:

$ cat f.rb
[snip]

This is nice… I wasn’t aware that Ruby has a ‘END’ tag.

ruby d.rb
before
middle
after
expand -2 d.rb
puts “before”
eval DATA.read
puts “after”
END
puts “middle”

Are there other sweet things like this?

lotsof
:wink:

robert