class Float
Constants
- BASE10_DIGITS
- BITSIZE
- SIZE
Public Instance Methods
accurate_to_s()
click to toggle source
# File lib/redparse/float_accurate_to_s.rb, line 29 def accurate_to_s #this shouldn't be needed anymore after 1.9.2 return "#{'-' if self<0}Infinity" if infinite? return "NaN" if nan? return to_s if zero? #-0.0 and +0.0 as_str=sprintf("%.#{BASE10_DIGITS+2}e",self) #decompose self into sign, mantissa, and exponent (in string form) all,sign,first,digits,exp=*as_str.match(/^([+-]?)(\d+)(?:\.(\d+))?(?:[eE](.*))?$/) digits=first<<(digits||'0') exp=(exp||'0').to_i+1 lead=sign<<"0." #recompose back to a float result=[lead,digits,"e",exp].join result_f=result.to_f delta=result_f - self return digits=digits if delta.zero? #if representation is exact, return here #figure out which direction to go to get toward the right answer if delta<0 incr=1 else #delta>0 incr=-1 end #keep adding increasing increments to mantissa #until we get to a value on the other side of the correct answer 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]==?- #can't happen... I think? trying=[lead,try_digits,"e",exp].join trying_f=trying.to_f break unless trying_f.zero? digits[-1,1]='' #workaround 1.8 bug end return digits=try_digits if trying_f==self break if self.between?(*[trying_f,result_f].sort) #(trying_f-self)*delta<0 incr*=2 end #we now have lower and upper bounds on the correct answer lower,upper=*[digits.to_i, digits.to_i.+(incr)].sort #maybe one of the bounds is already the correct answer? 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 #binary search between lower and upper bounds til we find a correct answer digits=nil while true return as_str if upper-lower <= 1 #hopeless 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 #mid_f>self upper=mid end end ensure #try to drop unneeded trailing digits 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