Class: Float

Inherits:
Object
  • Object
show all
Includes:
Nio::Formattable
Defined in:
lib/nio/fmt.rb,
lib/nio/sugar.rb,
lib/nio/flttol.rb,
lib/nio/flttol.rb,
lib/nio/rtnlzr.rb,
lib/nio/rtnlzr.rb

Constant Summary collapse

RADIX =

Base of the Float representation

2
MANT_DIG =

Number of RADIX-base digits of precision in a Float

_bits_
DIG =

Number of decimal digits that can be stored in a Float and recovered

((MANT_DIG-1)*Math.log(RADIX)/Math.log(10)).floor
EPSILON =

Smallest value that added to 1.0 produces something different from 1.0

Math.ldexp(*Math.frexp(1).collect{|e| e.kind_of?(Integer) ? e-(MANT_DIG-1) : e})
DECIMAL_DIG =

Decimal precision required to represent a Float and be able to recover its value

(MANT_DIG*Math.log(RADIX)/Math.log(10)).ceil+1

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Nio::Formattable

append_features, #nio_round, #nio_write

Class Method Details

.nio_read_neutral(neutral) ⇒ Object



1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
# File 'lib/nio/fmt.rb', line 1507

def self.nio_read_neutral(neutral)   
  x = nil
  
  honor_rounding = true
  
  if neutral.special?
    case neutral.special
      when :nan
        x = 0.0/0.0
      when :inf
        x = (neutral.sign=='-' ? -1.0 : +1.0)/0.0
    end
  elsif neutral.rep_pos<neutral.digits.length  
    
    x,y = neutral.to_RepDec.getQ
    x = Float(x)/y
    
  else
    nd = neutral.base==10 ? Float::DIG : ((Float::MANT_DIG-1)*Math.log(2)/Math.log(neutral.base)).floor 
    k = neutral.dec_pos-neutral.digits.length
    if !honor_rounding && (neutral.digits.length<=nd && k.abs<=15)
      x = neutral.digits.to_i(neutral.base).to_f
      if k<0
        x /= Float(neutral.base**-k)
      else
        x *= Float(neutral.base**k)
      end
      x = -x if neutral.sign=='-'
    elsif !honor_rounding && (k>0 && (k+neutral.digits.length < 2*nd))
      j = k-neutral.digits.length
      x = neutral.digits.to_i(neutral.base).to_f * Float(neutral.base**(j))
      x *= Float(neutral.base**(k-j))
      x = -x if neutral.sign=='-'
    elsif neutral.base.modulo(Float::RADIX)==0
     
     f = neutral.digits.to_i(neutral.base)
     e = neutral.dec_pos-neutral.digits.length

     rounding = neutral.rounding
     
     x = Nio::Clinger::algM(f,e,rounding,neutral.base,Float::RADIX,Float::MANT_DIG,Float::MIN_EXP-Float::MANT_DIG,Float::MAX_EXP-Float::MANT_DIG)
     x = -x if neutral.sign=='-'
     
    else
     
     f = neutral.digits.to_i(neutral.base)
     e = neutral.dec_pos-neutral.digits.length

     rounding = neutral.rounding
     
     x = Nio::Clinger::algM(f,e,rounding,neutral.base,Float::RADIX,Float::MANT_DIG,Float::MIN_EXP-Float::MANT_DIG,Float::MAX_EXP-Float::MANT_DIG)
     x = -x if neutral.sign=='-'
     
    end
  end
   
  return x
end

Instance Method Details

#_to_iObject



56
# File 'lib/nio/flttol.rb', line 56

alias _to_i to_i

#nio_r(tol = Nio::Tolerance.big_epsilon) ⇒ Object

Conversion to Rational. The optional argument must be one of:

  • a Nio::Tolerance that defines the admisible tolerance; in that case, the smallest denominator rational within the tolerance will be found (which may take a long time for small tolerances.)

  • an integer that defines a maximum value for the denominator. in which case, the best approximation with that maximum denominator will be returned.



110
111
112
113
114
115
116
117
# File 'lib/nio/rtnlzr.rb', line 110

def nio_r(tol = Nio::Tolerance.big_epsilon)
  case tol
    when Integer
      Rational(*Nio::Rtnlzr.max_denominator(self,tol,Float))
    else
      Rational(*Nio::Rtnlzr.new(Nio::Tol(tol)).rationalize(self))      
  end
end

#nio_write_neutral(fmt) ⇒ Object



1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
# File 'lib/nio/fmt.rb', line 1565

def nio_write_neutral(fmt)
  neutral = Nio::NeutralNum.new
  x = self
  
  if x.nan?
    neutral.set_special(:nan)
  elsif x.infinite?
    neutral.set_special(:inf, x<0 ? '-' : '+')
  else
    converted = false
    if fmt.get_ndig==:exact && fmt.get_approx==:simplify
      
      if x!=0
        q = x.nio_r(Nio::Tolerance.decimals(Float::DIG,:sig))
        if q!=0
          neutral = q.nio_write_neutral(fmt)
          converted = true if neutral.digits.length<=Float::DIG
        end
      end
      
    elsif fmt.get_approx==:exact
      neutral = x.nio_xr.nio_write_neutral(fmt)
      converted = true
    end
    if !converted  
      if fmt.get_base==10 && false
        txt = format "%.*e",Float::DECIMAL_DIG-1,x # note that spec. e output precision+1 significant digits
        
        sign = '+'    
        if txt[0,1]=='-'
          sign = '-'
          txt = txt[1...txt.length]
        end
        exp = 0
        x_char = fmt.get_exp_char(fmt.get_base)

        exp_i = txt.index(x_char)
        exp_i = txt.index(x_char.downcase) if exp_i===nil
        if exp_i!=nil
          exp = txt[exp_i+1...txt.length].to_i
          txt = txt[0...exp_i] 
        end    
        
        dec_pos = txt.index '.'
        if dec_pos==nil
          dec_pos = txt.length 
        else
          txt[dec_pos]=''
        end
        dec_pos += exp
        neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits(10), true, fmt.get_round
        
        converted = true
      end
    end
    if !converted
      
      sign = x<0 ? '-' : '+'
      x = -x if sign=='-'
      f,e = Math.frexp(x)
      if e < Float::MIN_EXP
        # denormalized number
        f = Math.ldexp(f,e-Float::MIN_EXP+Float::MANT_DIG)
        e = Float::MIN_EXP-Float::MANT_DIG
      else
        # normalized number
        f = Math.ldexp(f,Float::MANT_DIG)
        e -= Float::MANT_DIG
      end
      f = f.to_i
      inexact = true

      rounding = fmt.get_round
      
      if fmt.get_all_digits?
        # use as many digits as possible
        dec_pos,r,*digits = Nio::BurgerDybvig::float_to_digits_max(x,f,e,rounding,Float::MIN_EXP-Float::MANT_DIG,Float::MANT_DIG,Float::RADIX,fmt.get_base)
        inexact = :roundup if r
      else
        # use as few digits as possible
        dec_pos,*digits = Nio::BurgerDybvig::float_to_digits(x,f,e,rounding,Float::MIN_EXP-Float::MANT_DIG,Float::MANT_DIG,Float::RADIX,fmt.get_base)
      end
      txt = ''
      digits.each{|d| txt << fmt.get_base_digits.digit_char(d)}
      neutral.set sign, txt, dec_pos, nil, fmt.get_base_digits, inexact, fmt.get_round
      
    end
  end
       
  return neutral
end

#nio_xrObject

Conversion to Rational preserving the exact value of the number.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/nio/rtnlzr.rb', line 39

def nio_xr
  return Rational(self.to_i,1) if self.modulo(1)==0
  if !self.finite?
    return Rational(0,0) if self.nan?
    return self<0 ? Rational(-1,0) : Rational(1,0)
  end
  
  f,e = Math.frexp(self)
      
  if e < Float::MIN_EXP
     bits = e+Float::MANT_DIG-Float::MIN_EXP
  else
     bits = [Float::MANT_DIG,e].max  
     #return Rational(self.to_i,1) if bits<e
  end      
    p = Math.ldexp(f,bits)
    e = bits - e
    if e<Float::MAX_EXP
      q = Math.ldexp(1,e)
    else
      q = Float::RADIX**e
    end
  return Rational(p.to_i,q.to_i)
end

#to_iObject



57
58
59
60
61
62
63
# File 'lib/nio/flttol.rb', line 57

def to_i
  neg = (self < 0)
  i = _to_i
  i_neg = (i < 0)
  i = -i if neg != i_neg
  i
end

#to_r(tol = Nio::Tolerance.big_epsilon) ⇒ Object



88
89
90
# File 'lib/nio/sugar.rb', line 88

def to_r(tol = Nio::Tolerance.big_epsilon)
  nio_r(tol)
end