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

G

Gavin Kistner

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.)
 
E

Elias Athanasopoulos

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;
-
+
if (isinf(value))
return rb_str_new2(value < 0 ? "-Infinity" : "Infinity");
else if(isnan(value))
 
N

nobu.nokada

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";
}
 
E

Elias Athanasopoulos

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".

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

Regards,
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: 5.000...007.to_s => "5""

|> 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.
 
N

nobu.nokada

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";
}
 
N

nobu.nokada

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);
 
S

Simon Strandgaard

$ cat f.rb
[snip]

This is nice.. I wasn't aware that Ruby has a '__END__' tag.

server> ruby d.rb
before
middle
after
server> expand -2 d.rb
puts "before"
eval DATA.read
puts "after"
__END__
puts "middle"
server>

Are there other sweet things like this?
 
R

Robert Klemme

Simon Strandgaard said:
$ cat f.rb
[snip]

This is nice.. I wasn't aware that Ruby has a '__END__' tag.

server> ruby d.rb
before
middle
after
server> expand -2 d.rb
puts "before"
eval DATA.read
puts "after"
__END__
puts "middle"
server>

Are there other sweet things like this?

lotsof
;-)

robert
 
H

H.Yamamoto

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')
 
H

H.Yamamoto

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,528
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top