11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
# File 'lib/ron/float_accurate_to_s.rb', line 11
def accurate_to_s
return "#{'-' if self<0}Infinity" if infinite?
return "NaN" if nan?
return "0.0e0" if zero?
as_str=sprintf("%.#{BASE10_DIGITS+2}e",self)
all,sign,first,digits,exp=*as_str.match(/^([+-]?)(\d)\.(\d+)e(.*)$/)
digits=first<<digits
exp=exp.to_i+1
lead=sign<<"0."
return digits=digits if as_str.to_f.zero?
result=[lead,digits,"e",exp].join
result_f=result.to_f
delta=result_f - self
return digits=digits if delta.zero?
if delta<0
incr=1
else incr=-1
end
while true
while true
try_digits=digits.to_i.+(incr).to_s
if try_digits.size>digits.size
exp+=1
digits="0"+digits
end
fail if try_digits[0]==?- trying=[lead,try_digits,"e",exp].join
trying_f=trying.to_f
break unless trying_f.zero?
digits[-1,1]='' end
return digits=try_digits if trying_f==self
break if self.between?(*[trying_f,result_f].sort) incr*=2
end
lower,upper=*[digits.to_i, digits.to_i.+(incr)].sort
result=[lead,lower,"e",exp].join
return digits=lower if result.to_f==self
result=[lead,upper,"e",exp].join
return digits=upper if result.to_f==self
digits=nil
while true
return as_str if upper-lower <= 1 mid=(lower+upper)/2
mid_s=[lead,mid,"e",exp].join
mid_f=mid_s.to_f
return digits=mid if mid_f==self
if mid_f<self
lower=mid
else upper=mid
end
end
ensure
if digits
digits=digits.to_s
begin
last=digits.slice! -1
result=[lead,digits,"e",exp].join.to_f
end while result==self or result.zero? && digits.size.nonzero?
roundup=(digits.to_i+1).to_s
if roundup.size>digits.size
exp+=1
digits="0"+digits
end
roundup.slice! /0+\Z/
roundup=[lead,roundup,"e",exp].join
return roundup if roundup.to_f==self
return [lead,digits<<last,"e",exp].join
end
end
|