Parent

Included Modules

Class Index [+]

Quicksearch

Flt::Num

Generic radix arbitrary-precision, floating-point numbers. This is a base class for floating point types of specific radix.

The implementation of floating-point arithmetic is largely based on the Decimal module of Python, written by Eric Price, Facundo Batista, Raymond Hettinger, Aahz and Tim Peters.

Constants

ROUND_HALF_EVEN
ROUND_HALF_DOWN
ROUND_HALF_UP
ROUND_FLOOR
ROUND_CEILING
ROUND_DOWN
ROUND_UP
ROUND_05UP
EXCEPTIONS

Attributes

_base_coercible_types[R]
_base_conversions[R]

Public Class Methods

Context(*args) click to toggle source

Context constructor; if an options hash is passed, the options are applied to the default context; if a Context is passed as the first argument, it is used as the base instead of the default context.

Note that this method should be called on concrete floating point types such as Flt::DecNum and Flt::BinNum, and not in the abstract base class Flt::Num.

See Flt::Num::ContextBase#new() for the valid options

      # File lib/flt/num.rb, line 1159
1159:   def self.Context(*args)
1160:     case args.size
1161:       when 0
1162:         base = self::DefaultContext
1163:       when 1
1164:         arg = args.first
1165:         if arg.instance_of?(self::Context)
1166:           base = arg
1167:           options = nil
1168:         elsif arg.instance_of?(Hash)
1169:           base = self::DefaultContext
1170:           options = arg
1171:         else
1172:           raise TypeError,"invalid argument for #{num_class}.Context"
1173:         end
1174:       when 2
1175:         base = args.first
1176:         options = args.last
1177:       else
1178:         raise ArgumentError,"wrong number of arguments (#{args.size} for 0, 1 or 2)"
1179:     end
1180: 
1181:     if options.nil? || options.empty?
1182:       base
1183:     else
1184:       self::Context.new(base, options)
1185:     end
1186: 
1187:   end
Flags(*values) click to toggle source
     # File lib/flt/num.rb, line 365
365:   def self.Flags(*values)
366:     Flt::Support::Flags(EXCEPTIONS,*values)
367:   end
Num(*args) click to toggle source

Num is the general constructor that can be invoked on specific Flt::Num-derived classes.

      # File lib/flt/num.rb, line 1493
1493:     def Num(*args)
1494:       if args.size==1 && args.first.instance_of?(self)
1495:         args.first
1496:       else
1497:         new(*args)
1498:       end
1499:     end
base_coercible_types() click to toggle source
     # File lib/flt/num.rb, line 144
144:     def base_coercible_types
145:       Num._base_coercible_types
146:     end
base_conversions() click to toggle source
     # File lib/flt/num.rb, line 147
147:     def base_conversions
148:       Num._base_conversions
149:     end
ccontext(*args) click to toggle source
     # File lib/flt/complex.rb, line 274
274:     def self.ccontext(*args)
275:       ComplexContext(self.context(*args))
276:     end
context(*args, &blk) click to toggle source

The current context (thread-local). If arguments are passed they are interpreted as in Num.define_context() and an altered copy of the current context is returned. If a block is given, this method is a synonym for Num.local_context().

      # File lib/flt/num.rb, line 1213
1213:   def self.context(*args, &blk)
1214:     if blk
1215:       # setup a local context
1216:       local_context(*args, &blk)
1217:     elsif args.empty?
1218:       # return the current context
1219:       ctxt = self._context
1220:       self._context = ctxt = self::DefaultContext.dup if ctxt.nil?
1221:       ctxt
1222:     else
1223:       # Return a modified copy of the current context
1224:       if args.first.kind_of?(ContextBase)
1225:         self.define_context(*args)
1226:       else
1227:         self.define_context(self.context, *args)
1228:       end
1229:     end
1230:   end
context=(c) click to toggle source

Change the current context (thread-local).

      # File lib/flt/num.rb, line 1233
1233:   def self.context=(c)
1234:     self._context = c.dup
1235:   end
define_context(*options) click to toggle source

Define a context by passing either of:

  • A Context object (of the same type)

  • A hash of options (or nothing) to alter a copy of the current context.

  • A Context object and a hash of options to alter a copy of it

      # File lib/flt/num.rb, line 1193
1193:   def self.define_context(*options)
1194:     context = options.shift if options.first.instance_of?(self::Context)
1195:     if context && options.empty?
1196:       context
1197:     else
1198:       context ||= self.context
1199:       self.Context(context, *options)
1200:     end
1201:   end
infinity(sign=+1) click to toggle source

A floating-point infinite number with the specified sign

      # File lib/flt/num.rb, line 1293
1293:     def infinity(sign=1)
1294:       new [sign, 0, :inf]
1295:     end
int_div_radix_power(x,n) click to toggle source
      # File lib/flt/num.rb, line 1315
1315:     def int_div_radix_power(x,n)
1316:       n < 0 ? (x * self.radix**(-n) ) : (x / self.radix**n)
1317:     end
int_mult_radix_power(x,n) click to toggle source
      # File lib/flt/num.rb, line 1311
1311:     def int_mult_radix_power(x,n)
1312:       n < 0 ? (x / self.radix**(-n)) : (x * self.radix**n)
1313:     end
int_radix_power(n) click to toggle source
      # File lib/flt/num.rb, line 1307
1307:     def int_radix_power(n)
1308:       self.radix**n
1309:     end
local_context(*args) click to toggle source

Defines a scope with a local context. A context can be passed which will be set a the current context for the scope; also a hash can be passed with options to apply to the local scope. Changes done to the current context are reversed when the scope is exited.

      # File lib/flt/num.rb, line 1246
1246:   def self.local_context(*args)
1247:     begin
1248:       keep = self.context # use this so _context is initialized if necessary
1249:       self.context = define_context(*args) # this dups the assigned context
1250:       result = yield _context
1251:     ensure
1252:       # TODO: consider the convenience of copying the flags from DecNum.context to keep
1253:       # This way a local context does not affect the settings of the previous context,
1254:       # but flags are transferred.
1255:       # (this could be done always or be controlled by some option)
1256:       #   keep.flags = DecNum.context.flags
1257:       # Another alternative to consider: logically or the flags:
1258:       #   keep.flags ||= DecNum.context.flags # (this requires implementing || in Flags)
1259:       self._context = keep
1260:       result
1261:     end
1262:   end
math(*args, &blk) click to toggle source
      # File lib/flt/num.rb, line 1319
1319:     def math(*args, &blk)
1320:       self.context.math(*args, &blk)
1321:     end
nan() click to toggle source

A floating-point NaN (not a number)

      # File lib/flt/num.rb, line 1298
1298:     def nan()
1299:       new [1, nil, :nan]
1300:     end
new(*args) click to toggle source

A floating point-number value can be defined by:

  • A String containing a text representation of the number

  • An Integer

  • A Rational

  • For binary floating point: a Float

  • A Value of a type for which conversion is defined in the context.

  • Another floating-point value of the same type.

  • A sign, coefficient and exponent (either as separate arguments, as an array or as a Hash with symbolic keys), or a signed coefficient and an exponent. This is the internal representation of Num, as returned by Num#split. The sign is +1 for plus and -1 for minus; the coefficient and exponent are integers, except for special values which are defined by :inf, :nan or :snan for the exponent.

An optional Context can be passed after the value-definint argument to override the current context and options can be passed in a last hash argument; alternatively context options can be overriden by options of the hash argument.

When the number is defined by a numeric literal (a String), it can be followed by a symbol that specifies the mode used to convert the literal to a floating-point value:

  • :free is currently the default for all cases. The precision of the input literal (including trailing zeros) is preserved and the precision of the context is ignored. When the literal is in the same base as the floating-point radix, (which, by default, is the case for DecNum only), the literal is preserved exactly in floating-point. Otherwise, all significative digits that can be derived from the literal are generanted, significative meaning here that if the digit is changed and the value converted back to a literal of the same base and precision, the original literal will not be obtained.

  • :short is a variation of :free in which only the minimun number of digits that are necessary to produce the original literal when the value is converted back with the same original precision.

  • :fixed will round and normalize the value to the precision specified by the context (normalize meaning that exaclty the number of digits specified by the precision will be generated, even if the original literal has fewer digits.) This may fail returning NaN (and raising Inexact) if the context precision is :exact, but not if the floating-point radix is a multiple of the input base.

Options that can be passed for construction from literal:

  • :base is the numeric base of the input, 10 by default.

      # File lib/flt/num.rb, line 1360
1360:   def initialize(*args)
1361:     options = args.pop if args.last.is_a?(Hash)
1362:     context = args.pop if args.size>0 && (args.last.kind_of?(ContextBase) || args.last.nil?)
1363:     context ||= options && options.delete(:context)
1364:     mode = args.pop if args.last.is_a?(Symbol) && ![:inf, :nan, :snan].include?(args.last)
1365:     args = args.first if args.size==1 && args.first.is_a?(Array)
1366:     if args.empty? && options
1367:       args = [options.delete(:sign)||1,
1368:               options.delete(:coefficient) || 0,
1369:               options.delete(:exponent) || 0]
1370:     end
1371:     mode ||= options && options.delete(:mode)
1372:     base = (options && options.delete(:base)) || 10
1373:     context = options if context.nil? && options && !options.empty?
1374:     context = define_context(context)
1375: 
1376:     case args.size
1377:     when 3
1378:       # internal representation
1379:       @sign, @coeff, @exp = args
1380:       # TO DO: validate
1381: 
1382:     when 2
1383:       # signed integer and scale
1384:       @coeff, @exp = args
1385:       if @coeff < 0
1386:         @sign = 1
1387:         @coeff = -@coeff
1388:       else
1389:         @sign = 1
1390:       end
1391: 
1392:     when 1
1393:       arg = args.first
1394:       case arg
1395: 
1396:       when num_class
1397:         @sign, @coeff, @exp = arg.split
1398: 
1399:       when *context.coercible_types
1400:         v = context._coerce(arg)
1401:         @sign, @coeff, @exp = v.is_a?(Num) ? v.split : v
1402: 
1403:       when String
1404:         if arg.strip != arg
1405:           @sign,@coeff,@exp = context.exception(ConversionSyntax, "no trailing or leading whitespace is permitted").split
1406:           return
1407:         end
1408:         m = _parser(arg)
1409:         if m.nil?
1410:           @sign,@coeff,@exp = context.exception(ConversionSyntax, "Invalid literal for DecNum: #{arg.inspect}").split
1411:           return
1412:         end
1413:         @sign = (m.sign == '-') ? 1 : 1
1414:         if m.int || m.onlyfrac
1415:           sign = @sign
1416:           if m.int
1417:             intpart = m.int
1418:             fracpart = m.frac
1419:           else
1420:             intpart = ''
1421:             fracpart = m.onlyfrac
1422:           end
1423:           exp = m.exp.to_i
1424:           if fracpart
1425:             coeff = (intpart+fracpart).to_i(base)
1426:             exp -= fracpart.size
1427:           else
1428:             coeff = intpart.to_i(base)
1429:           end
1430: 
1431:           if false
1432:             # Old behaviour: use :fixed format when num_class.radix != base
1433:             # Advantages:
1434:             # * Behaviour similar to Float: BinFloat(txt) == Float(txt)
1435:             mode ||= ((num_class.radix == base) ? :free : :fixed)
1436:           else
1437:             # New behaviour: the default is always :free
1438:             # Advantages:
1439:             # * Is coherent with construction of DecNum from decimal literal:
1440:             #   preserve precision of the literal with independence of context.
1441:             mode ||= :free
1442:           end
1443: 
1444:           if [:free, :short].include?(mode) && base == num_class.radix
1445:             # simple case, the job is already done
1446:           else
1447:             rounding = context.rounding
1448:             reader = Support::Reader.new(:mode=>mode)
1449:             ans = reader.read(context, rounding, sign, coeff, exp, base)
1450:             context.exception(Inexact,"Inexact decimal to radix #{num_class.radix} conversion") if !reader.exact?
1451:             if !reader.exact? && context.exact?
1452:               sign, coeff, exp =  num_class.nan.split
1453:             else
1454:               sign, coeff, exp = ans.split
1455:             end
1456:           end
1457:           @sign, @coeff, @exp = sign, coeff, exp
1458:         else
1459:           if m.diag
1460:             # NaN
1461:             @coeff = (m.diag.nil? || m.diag.empty?) ? nil : m.diag.to_i
1462:             @coeff = nil if @coeff==0
1463:              if @coeff
1464:                max_diag_len = context.maximum_nan_diagnostic_digits
1465:                if max_diag_len && @coeff >= context.int_radix_power(max_diag_len)
1466:                   @sign,@coeff,@exp = context.exception(ConversionSyntax, "diagnostic info too long in NaN").split
1467:                  return
1468:                end
1469:              end
1470:             @exp = m.signal ? :snan : :nan
1471:           else
1472:             # Infinity
1473:             @coeff = 0
1474:             @exp = :inf
1475:           end
1476:         end
1477:       else
1478:         raise TypeError, "invalid argument #{arg.inspect}"
1479:       end
1480:     else
1481:       raise ArgumentError, "wrong number of arguments (#{args.size} for 1, 2 or 3)"
1482:     end
1483:   end
num_class() click to toggle source
      # File lib/flt/num.rb, line 1281
1281:     def num_class
1282:       self
1283:     end
one_half() click to toggle source

One half: 1/2

      # File lib/flt/num.rb, line 1303
1303:     def one_half
1304:       new '0.5'
1305:     end
set_context(*args) click to toggle source

Modify the current context, e.g. DecNum.set_context(:precision=>10)

      # File lib/flt/num.rb, line 1238
1238:   def self.set_context(*args)
1239:     self.context = define_context(*args)
1240:   end
zero(sign=+1) click to toggle source

A floating-point number with value zero and the specified sign

      # File lib/flt/num.rb, line 1288
1288:     def zero(sign=1)
1289:       new [sign, 0, 0]
1290:     end

Protected Class Methods

[](*args) click to toggle source

Num[base] can be use to obtain a floating-point numeric class with radix base, so that, for example, Num[2] is equivalent to BinNum and Num[10] to DecNum.

If the base does not correspond to one of the predefined classes (DecNum, BinNum), a new class is dynamically generated.

The [] operator can also be applied to classes derived from Num to act as a constructor (short hand for .new):

  Flt::Num[10]['0.1'] # same as FLt::DecNum['0.1'] or Flt.DecNum('0.1') or Flt::DecNum.new('0.1')
      # File lib/flt/num.rb, line 4350
4350:     def [](*args)
4351:       return self.Num(*args) if self!=Num # && self.ancestors.include?(Num)
4352:       raise RuntimeError, "Invalid number of arguments (#{args.size}) for Num.[]; 1 expected." unless args.size==1
4353:       base = args.first
4354: 
4355:       case base
4356:       when 10
4357:         DecNum
4358:       when 2
4359:         BinNum
4360:       else
4361:         class_name = "Base#{base}Num"
4362:         unless Flt.const_defined?(class_name)
4363:           cls = Flt.const_set class_name, Class.new(Num) {
4364:             def initialize(*args)
4365:               super(*args)
4366:             end
4367:           }
4368:           meta_cls = class <<cls;self;end
4369:           meta_cls.send :define_method, :radix do
4370:             base
4371:           end
4372: 
4373:           cls.const_set :Context, Class.new(Num::ContextBase)
4374:           cls::Context.send :define_method, :initialize do |*options|
4375:             super(cls, *options)
4376:           end
4377: 
4378:           default_digits = 10
4379:           default_elimit = 100
4380: 
4381:           cls.const_set :DefaultContext, cls::Context.new(
4382:             :exact=>false, :precision=>default_digits, :rounding=>:half_even,
4383:             :elimit=>default_elimit,
4384:             :flags=>[],
4385:             :traps=>[DivisionByZero, Overflow, InvalidOperation],
4386:             :ignored_flags=>[],
4387:             :capitals=>true,
4388:             :clamp=>true,
4389:             :angle=>:rad
4390:           )
4391: 
4392:         end
4393:         Flt.const_get class_name
4394: 
4395:       end
4396:     end
convert(x, dest_base_or_class, *args) click to toggle source

Approximate base conversion.

Convert x to another Flt::Num class, so that if the result is converted to back to the original class with the same precision and rounding mode, the value is preserved, but use as few decimal digits as possible.

Optional parameters: a context and/or an options hash can be passed.

The context should be a context for the type of x, and is used to specified the precision and rounding mode requiered to restore the original value from the converted value.

The options are:

  • :rounding used to specify the rounding required for back conversion with precedence over the context; the value :nearest means any round-to-nearest.

  • :all_digits to preserve the input precision by using all significant digits in the output, not just the minimum required

  • :minimum_precision to specify a minimum for the precision

To increment the result number of digits x can be normalized or its precision (quantum) changed, or use the :minimum_precision option.

      # File lib/flt/num.rb, line 4458
4458:   def self.convert(x, dest_base_or_class, *args)
4459:     origin_context = args.shift if args.first.is_a?(ContextBase)
4460:     raise ArgumentError,"Invalid parameters for Num.convert" unless args.size<=1 && (args.empty? || args.first.is_a?(Hash))
4461:     options = args.first || {}
4462: 
4463:     rounding = options[:rounding]
4464:     all_digits = options[:all_digits] # :all_digits ? :shortest/:significative
4465:     minimum_precision = options[:minimum_precision]
4466: 
4467:     num_class = dest_base_or_class.is_a?(Integer) ? Num[dest_base_or_class] :  dest_base_or_class
4468:     if x.special?
4469:       if x.nan?
4470:         num_class.nan
4471:       else # x.infinite?
4472:         num_class.infinite(x.sign)
4473:       end
4474:     elsif x.zero?
4475:       num_class.zero(x.sign)
4476:     else
4477:       context = x.num_class.define_context(origin_context)
4478: 
4479:       p = x.number_of_digits
4480:       p = minimum_precision if minimum_precision && p<minimum_precision
4481:       s,f,e = x.split
4482:       rounding ||= context.rounding unless
4483:       formatter = Flt::Support::Formatter.new(x.num_class.radix, num_class.context.etiny, num_class.radix)
4484:       formatter.format(x, f, e, rounding, p, all_digits)
4485:       dec_pos,digits = formatter.adjusted_digits(rounding)
4486: 
4487:       # f = digits.map{|d| d.to_s(num_class.radix)}.join.to_i(num_class.radix)
4488:       f = digits.inject(0){|a,b| a*num_class.radix + b}
4489:       e = dec_pos - digits.size
4490:       num_class.Num(s, f, e)
4491:     end
4492:   end
convert_exact(x, dest_base_or_class, dest_context=nil) click to toggle source

Exact base conversion: preserve x value.

Convert x to a Flt::Num of the specified base or class If the dest_context is exact, this may raise the Inexact flag (and return NaN), for some cases (e.g. converting DecNum(‘0.1’) to BinNum)

The current destination context (overriden by dest_context) determines the valid range and the precision (if its is not :exact the result will be rounded)

      # File lib/flt/num.rb, line 4407
4407:   def self.convert_exact(x, dest_base_or_class, dest_context=nil)
4408:     num_class = dest_base_or_class.is_a?(Integer) ? Num[dest_base_or_class] :  dest_base_or_class
4409:     if x.special?
4410:       if x.nan?
4411:         num_class.nan
4412:       else # x.infinite?
4413:         num_class.infinity(x.sign)
4414:       end
4415:     elsif x.zero?
4416:       num_class.zero(x.sign)
4417:     else
4418:       if dest_base_or_class == Float
4419:         float = true
4420:         num_class = BinNum
4421:         dest_context = BinNum::FloatContext
4422:       end
4423:       y = num_class.context(dest_context) do
4424:         sign, coeff, exp = x.split
4425:         y = num_class.Num(sign*coeff)
4426:         if exp < 0
4427:           y /= x.num_class.int_radix_power(-exp)
4428:         else
4429:           y *= x.num_class.int_radix_power(exp)
4430:         end
4431:         # y.reduce
4432:       end
4433:       y = y.to_f if float
4434:       y
4435:     end
4436:   end
initialize(*args) click to toggle source
      # File lib/flt/num.rb, line 4364
4364:             def initialize(*args)
4365:               super(*args)
4366:             end

Public Instance Methods

%(other, context=nil) click to toggle source

Modulo of two decimal numbers

      # File lib/flt/num.rb, line 1646
1646:   def %(other, context=nil)
1647:     _bin_op :%, :modulo, other, context
1648:   end
*(other, context=nil) click to toggle source

Multiplication of two decimal numbers

      # File lib/flt/num.rb, line 1636
1636:   def *(other, context=nil)
1637:     _bin_op :*, :multiply, other, context
1638:   end
**(other, context=nil) click to toggle source

Power

      # File lib/flt/num.rb, line 1651
1651:   def **(other, context=nil)
1652:     _bin_op :**, :power, other, context
1653:   end
+(other, context=nil) click to toggle source

Addition of two decimal numbers

      # File lib/flt/num.rb, line 1626
1626:   def +(other, context=nil)
1627:     _bin_op :+, :add, other, context
1628:   end
+@(context=nil) click to toggle source

Unary plus operator

      # File lib/flt/num.rb, line 1620
1620:   def +@(context=nil)
1621:     #(context || num_class.context).plus(self)
1622:     _pos(context)
1623:   end
-(other, context=nil) click to toggle source

Subtraction of two decimal numbers

      # File lib/flt/num.rb, line 1631
1631:   def -(other, context=nil)
1632:     _bin_op :-, :subtract, other, context
1633:   end
-@(context=nil) click to toggle source

Unary minus operator

      # File lib/flt/num.rb, line 1614
1614:   def -@(context=nil)
1615:     #(context || num_class.context).minus(self)
1616:     _neg(context)
1617:   end
/(other, context=nil) click to toggle source

Division of two decimal numbers

      # File lib/flt/num.rb, line 1641
1641:   def /(other, context=nil)
1642:     _bin_op :/, :divide, other, context
1643:   end
<=>(other) click to toggle source

Internal comparison operator: returns -1 if the first number is less than the second, 0 if both are equal or +1 if the first is greater than the secong.

      # File lib/flt/num.rb, line 2588
2588:   def <=>(other)
2589:     case other
2590:     when *num_class.context.coercible_types_or_num
2591:       other = Num(other)
2592:       if self.special? || other.special?
2593:         if self.nan? || other.nan?
2594:           1
2595:         else
2596:           self_v = self.finite? ? 0 : self.sign
2597:           other_v = other.finite? ? 0 : other.sign
2598:           self_v <=> other_v
2599:         end
2600:       else
2601:         if self.zero?
2602:           if other.zero?
2603:             0
2604:           else
2605:             -other.sign
2606:           end
2607:         elsif other.zero?
2608:           self.sign
2609:         elsif other.sign < self.sign
2610:           1
2611:         elsif self.sign < other.sign
2612:           1
2613:         else
2614:           self_adjusted = self.adjusted_exponent
2615:           other_adjusted = other.adjusted_exponent
2616:           if self_adjusted == other_adjusted
2617:             self_padded,other_padded = self.coefficient,other.coefficient
2618:             d = self.exponent - other.exponent
2619:             if d>0
2620:               self_padded *= num_class.int_radix_power(d)
2621:             else
2622:               other_padded *= num_class.int_radix_power(-d)
2623:             end
2624:             (self_padded <=> other_padded)*self.sign
2625:           elsif self_adjusted > other_adjusted
2626:             self.sign
2627:           else
2628:             -self.sign
2629:           end
2630:         end
2631:       end
2632:     else
2633:       if !self.nan? && defined? other.coerce
2634:         x, y = other.coerce(self)
2635:         x <=> y
2636:       else
2637:         nil
2638:       end
2639:     end
2640:   end
==(other) click to toggle source
      # File lib/flt/num.rb, line 2641
2641:   def ==(other)
2642:     (self<=>other) == 0
2643:   end
_abs(round=true, context=nil) click to toggle source

Returns a copy with positive sign

      # File lib/flt/num.rb, line 3380
3380:   def _abs(round=true, context=nil)
3381:     return copy_abs if not round
3382: 
3383:     if special?
3384:       ans = _check_nans(context)
3385:       return ans if ans
3386:     end
3387:     if sign>0
3388:       ans = _neg(context)
3389:     else
3390:       ans = _pos(context)
3391:     end
3392:     ans
3393:   end
_check_nans(context=nil, other=nil) click to toggle source

Check if the number or other is NaN, signal if sNaN or return NaN; return nil if none is NaN.

      # File lib/flt/num.rb, line 3276
3276:   def _check_nans(context=nil, other=nil)
3277:     #self_is_nan = self.nan?
3278:     #other_is_nan = other.nil? ? false : other.nan?
3279:     if self.nan? || (other && other.nan?)
3280:       context = define_context(context)
3281:       return context.exception(InvalidOperation, 'sNaN', self) if self.snan?
3282:       return context.exception(InvalidOperation, 'sNaN', other) if other && other.snan?
3283:       return self._fix_nan(context) if self.nan?
3284:       return other._fix_nan(context)
3285:     else
3286:       return nil
3287:     end
3288:   end
_fix(context) click to toggle source

Round if it is necessary to keep within precision.

      # File lib/flt/num.rb, line 3396
3396:   def _fix(context)
3397:     return self if context.exact?
3398: 
3399:     if special?
3400:       if nan?
3401:         return _fix_nan(context)
3402:       else
3403:         return Num(self)
3404:       end
3405:     end
3406: 
3407:     etiny = context.etiny
3408:     etop  = context.etop
3409:     if zero?
3410:       exp_max = context.clamp? ? etop : context.emax
3411:       new_exp = [[@exp, etiny].max, exp_max].min
3412:       if new_exp!=@exp
3413:         context.exception Clamped
3414:         return Num(sign,0,new_exp)
3415:       else
3416:         return Num(self)
3417:       end
3418:     end
3419: 
3420:     nd = number_of_digits
3421:     exp_min = nd + @exp - context.precision
3422:     if exp_min > etop
3423:       context.exception Inexact
3424:       context.exception Rounded
3425:       return context.exception(Overflow, 'above Emax', sign)
3426:     end
3427: 
3428:     self_is_subnormal = exp_min < etiny
3429: 
3430:     if self_is_subnormal
3431:       context.exception Subnormal
3432:       exp_min = etiny
3433:     end
3434: 
3435:     if @exp < exp_min
3436:       context.exception Rounded
3437:       # dig is the digits number from 0 (MS) to number_of_digits-1 (LS)
3438:       # dg = numberof_digits-dig is from 1 (LS) to number_of_digits (MS)
3439:       dg = exp_min - @exp # dig = number_of_digits + exp - exp_min
3440:       if dg > number_of_digits # dig<0
3441:         d = Num(sign,1,exp_min-1)
3442:         dg = number_of_digits # dig = 0
3443:       else
3444:         d = Num(self)
3445:       end
3446:       changed = d._round(context.rounding, dg)
3447:       coeff = num_class.int_div_radix_power(d.coefficient, dg)
3448:       coeff += 1 if changed==1
3449:       ans = Num(sign, coeff, exp_min)
3450:       if changed!=0
3451:         context.exception Inexact
3452:         if self_is_subnormal
3453:           context.exception Underflow
3454:           if ans.zero?
3455:             context.exception Clamped
3456:           end
3457:         elsif ans.number_of_digits == context.precision+1
3458:           if ans.exponent< etop
3459:             ans = Num(ans.sign, num_class.int_div_radix_power(ans.coefficient,1), ans.exponent+1)
3460:           else
3461:             ans = context.exception(Overflow, 'above Emax', d.sign)
3462:           end
3463:         end
3464:       end
3465:       return ans
3466:     end
3467: 
3468:     if context.clamp? &&  @exp>etop
3469:       context.exception Clamped
3470:       self_padded = num_class.int_mult_radix_power(@coeff, @exp-etop)
3471:       return Num(sign,self_padded,etop)
3472:     end
3473: 
3474:     return Num(self)
3475: 
3476:   end
_fix_nan(context) click to toggle source

adjust payload of a NaN to the context

      # File lib/flt/num.rb, line 3479
3479:   def _fix_nan(context)
3480:     if  !context.exact?
3481:       payload = @coeff
3482:       payload = nil if payload==0
3483: 
3484:       max_payload_len = context.maximum_nan_diagnostic_digits
3485: 
3486:       if number_of_digits > max_payload_len
3487:           payload = payload.to_s[-max_payload_len..1].to_i
3488:           return num_class.Num([@sign, payload, @exp])
3489:       end
3490:     end
3491:     Num(self)
3492:   end
_neg(context=nil) click to toggle source

Returns copy with sign inverted

      # File lib/flt/num.rb, line 3350
3350:   def _neg(context=nil)
3351:     if special?
3352:       ans = _check_nans(context)
3353:       return ans if ans
3354:     end
3355:     if zero?
3356:       ans = copy_abs
3357:     else
3358:       ans = copy_negate
3359:     end
3360:     context = define_context(context)
3361:     ans._fix(context)
3362:   end
_pos(context=nil) click to toggle source

Returns a copy with precision adjusted

      # File lib/flt/num.rb, line 3365
3365:   def _pos(context=nil)
3366:     if special?
3367:       ans = _check_nans(context)
3368:       return ans if ans
3369:     end
3370:     if zero?
3371:       ans = copy_abs
3372:     else
3373:       ans = Num(self)
3374:     end
3375:     context = define_context(context)
3376:     ans._fix(context)
3377:   end
_rescale(exp, rounding) click to toggle source

Rescale so that the exponent is exp, either by padding with zeros or by truncating digits, using the given rounding mode.

Specials are returned without change. This operation is quiet: it raises no flags, and uses no information from the context.

exp = exp to scale to (an integer) rounding = rounding mode

      # File lib/flt/num.rb, line 3299
3299:   def _rescale(exp, rounding)
3300: 
3301:     return Num(self) if special?
3302:     return Num(sign, 0, exp) if zero?
3303:     return Num(sign, @coeff*num_class.int_radix_power(self.exponent - exp), exp) if self.exponent > exp
3304:     #nd = number_of_digits + self.exponent - exp
3305:     nd = exp - self.exponent
3306:     if number_of_digits < nd
3307:       slf = Num(sign, 1, exp-1)
3308:       nd = number_of_digits
3309:     else
3310:       slf = num_class.new(self)
3311:     end
3312: 
3313:     changed = slf._round(rounding, nd)
3314:     coeff = num_class.int_div_radix_power(@coeff, nd)
3315:     coeff += 1 if changed==1
3316:     Num(slf.sign, coeff, exp)
3317: 
3318:   end
_watched_rescale(exp, context, watch_exp) click to toggle source
      # File lib/flt/num.rb, line 3320
3320:   def _watched_rescale(exp, context, watch_exp)
3321:     if !watch_exp
3322:       ans = _rescale(exp, context.rounding)
3323:       context.exception(Rounded) if ans.exponent > self.exponent
3324:       context.exception(Inexact) if ans != self
3325:       return ans
3326:     end
3327: 
3328:     if exp < context.etiny || exp > context.emax
3329:       return context.exception(InvalidOperation, "target operation out of bounds in quantize/rescale")
3330:     end
3331: 
3332:     return Num(@sign, 0, exp)._fix(context) if zero?
3333: 
3334:     self_adjusted = adjusted_exponent
3335:     return context.exception(InvalidOperation,"exponent of quantize/rescale result too large for current context") if self_adjusted > context.emax
3336:     return context.exception(InvalidOperation,"quantize/rescale has too many digits for current context") if (self_adjusted - exp + 1 > context.precision) && !context.exact?
3337: 
3338:     ans = _rescale(exp, context.rounding)
3339:     return context.exception(InvalidOperation,"exponent of rescale result too large for current context") if ans.adjusted_exponent > context.emax
3340:     return context.exception(InvalidOperation,"rescale result has too many digits for current context") if (ans.number_of_digits > context.precision) && !context.exact?
3341:     if ans.exponent > self.exponent
3342:       context.exception(Rounded)
3343:       context.exception(Inexact) if ans!=self
3344:     end
3345:     context.exception(Subnormal) if !ans.zero? && (ans.adjusted_exponent < context.emin)
3346:     return ans._fix(context)
3347:   end
abs(context=nil) click to toggle source

Absolute value

      # File lib/flt/num.rb, line 1891
1891:   def abs(context=nil)
1892:     if special?
1893:       ans = _check_nans(context)
1894:       return ans if ans
1895:     end
1896:     sign<0 ? _neg(context) : _pos(context)
1897:   end
add(other, context=nil) click to toggle source

Addition

      # File lib/flt/num.rb, line 1656
1656:   def add(other, context=nil)
1657: 
1658:     context = define_context(context)
1659:     other = _convert(other)
1660: 
1661:     if self.special? || other.special?
1662:       ans = _check_nans(context,other)
1663:       return ans if ans
1664: 
1665:       if self.infinite?
1666:         if self.sign != other.sign && other.infinite?
1667:           return context.exception(InvalidOperation, '-INF + INF')
1668:         end
1669:         return Num(self)
1670:       end
1671: 
1672:       return Num(other) if other.infinite?
1673:     end
1674: 
1675:     exp = [self.exponent, other.exponent].min
1676:     negativezero = (context.rounding == ROUND_FLOOR && self.sign != other.sign)
1677: 
1678:     if self.zero? && other.zero?
1679:       sign = [self.sign, other.sign].max
1680:       sign = 1 if negativezero
1681:       ans = Num([sign, 0, exp])._fix(context)
1682:       return ans
1683:     end
1684: 
1685:     if self.zero?
1686:       exp = [exp, other.exponent - context.precision - 1].max unless context.exact?
1687:       return other._rescale(exp, context.rounding)._fix(context)
1688:     end
1689: 
1690:     if other.zero?
1691:       exp = [exp, self.exponent - context.precision - 1].max unless context.exact?
1692:       return self._rescale(exp, context.rounding)._fix(context)
1693:     end
1694: 
1695:     op1, op2 = _normalize(self, other, context.precision)
1696: 
1697:     result_sign = result_coeff = result_exp = nil
1698:     if op1.sign != op2.sign
1699:       return ans = Num(negativezero ? 1 : 1, 0, exp)._fix(context) if op1.coefficient == op2.coefficient
1700:       op1,op2 = op2,op1 if op1.coefficient < op2.coefficient
1701:       result_sign = op1.sign
1702:       op1,op2 = op1.copy_negate, op2.copy_negate if result_sign < 0
1703:     elsif op1.sign < 0
1704:       result_sign = 1
1705:       op1,op2 = op1.copy_negate, op2.copy_negate
1706:     else
1707:       result_sign = 1
1708:     end
1709: 
1710:     if op2.sign == 1
1711:       result_coeff = op1.coefficient + op2.coefficient
1712:     else
1713:       result_coeff = op1.coefficient - op2.coefficient
1714:     end
1715: 
1716:     result_exp = op1.exponent
1717: 
1718:     return Num(result_sign, result_coeff, result_exp)._fix(context)
1719: 
1720:   end
adjusted_exponent() click to toggle source

Exponent of the magnitude of the most significant digit of the operand

      # File lib/flt/num.rb, line 2670
2670:   def adjusted_exponent
2671:     if special?
2672:       0
2673:     else
2674:       @exp + number_of_digits - 1
2675:     end
2676:   end
ceil(opt={}) click to toggle source

General ceiling operation (as for Float) with same options for precision as Flt::Num#round()

      # File lib/flt/num.rb, line 2966
2966:   def ceil(opt={})
2967:     opt[:rounding] = :ceiling
2968:     round opt
2969:   end
coefficient() click to toggle source

Significand as an integer, unsigned

      # File lib/flt/num.rb, line 2716
2716:   def coefficient
2717:     @coeff
2718:   end
coerce(other) click to toggle source

Used internally to convert numbers to be used in an operation to a suitable numeric type

      # File lib/flt/num.rb, line 1589
1589:   def coerce(other)
1590:     case other
1591:       when *num_class.context.coercible_types_or_num
1592:         [Num(other),self]
1593:       when Float
1594:         [other, self.to_f]
1595:       else
1596:         super
1597:     end
1598:   end
compare(other, context=nil) click to toggle source

Compares like <=> but returns a Num value.

      # File lib/flt/num.rb, line 2656
2656:   def compare(other, context=nil)
2657: 
2658:     other = _convert(other)
2659: 
2660:     if self.special? || other.special?
2661:       ans = _check_nans(context, other)
2662:       return ans if ans
2663:     end
2664: 
2665:     return Num(self <=> other)
2666: 
2667:   end
convert_to(type, context=nil) click to toggle source

Convert to other numerical type.

      # File lib/flt/num.rb, line 2484
2484:   def convert_to(type, context=nil)
2485:     context = define_context(context)
2486:     context.convert_to(type, self)
2487:   end
copy_abs() click to toggle source

Returns a copy of with the sign set to +

      # File lib/flt/num.rb, line 2750
2750:   def copy_abs
2751:     Num(1,@coeff,@exp)
2752:   end
copy_negate() click to toggle source

Returns a copy of with the sign inverted

      # File lib/flt/num.rb, line 2755
2755:   def copy_negate
2756:     Num(-@sign,@coeff,@exp)
2757:   end
copy_sign(other) click to toggle source

Returns a copy of with the sign of other

      # File lib/flt/num.rb, line 2760
2760:   def copy_sign(other)
2761:     sign = other.respond_to?(:sign) ? other.sign : ((other < 0) ? 1 : 1)
2762:     Num(sign, @coeff, @exp)
2763:   end
digits() click to toggle source

Digits of the significand as an array of integers

      # File lib/flt/num.rb, line 2695
2695:   def digits
2696:     @coeff.to_s(num_class.radix).split('').map{|d| d.to_i} # TODO: optimize in derivided classes
2697:   end
div(other, context=nil) click to toggle source

Ruby-style integer division: (x/y).floor

      # File lib/flt/num.rb, line 2103
2103:   def div(other, context=nil)
2104:     context = define_context(context)
2105:     other = _convert(other)
2106: 
2107:     ans = _check_nans(context,other)
2108:     return [ans,ans] if ans
2109: 
2110:     sign = self.sign * other.sign
2111: 
2112:     if self.infinite?
2113:       return context.exception(InvalidOperation, 'INF // INF') if other.infinite?
2114:       return num_class.infinity(sign)
2115:     end
2116: 
2117:     if other.zero?
2118:       if self.zero?
2119:         return context.exception(DivisionUndefined, '0 // 0')
2120:       else
2121:         return context.exception(DivisionByZero, 'x // 0', sign)
2122:       end
2123:     end
2124:     return self._divide_floor(other, context).first
2125:   end
divide(other, context=nil) click to toggle source

Division

      # File lib/flt/num.rb, line 1765
1765:   def divide(other, context=nil)
1766:     context = define_context(context)
1767:     other = _convert(other)
1768:     resultsign = self.sign * other.sign
1769:     if self.special? || other.special?
1770:       ans = _check_nans(context,other)
1771:       return ans if ans
1772:       if self.infinite?
1773:         return context.exception(InvalidOperation,"(+-)INF/(+-)INF") if other.infinite?
1774:         return num_class.infinity(resultsign)
1775:       end
1776:       if other.infinite?
1777:         context.exception(Clamped,"Division by infinity")
1778:         return num_class.new([resultsign, 0, context.etiny])
1779:       end
1780:     end
1781: 
1782:     if other.zero?
1783:       return context.exception(DivisionUndefined, '0 / 0') if self.zero?
1784:       return context.exception(DivisionByZero, 'x / 0', resultsign)
1785:     end
1786: 
1787:     if self.zero?
1788:       exp = self.exponent - other.exponent
1789:       coeff = 0
1790:     else
1791:       prec = context.exact? ? self.number_of_digits + 4*other.number_of_digits : context.precision
1792:       shift = other.number_of_digits - self.number_of_digits + prec
1793:       shift += 1
1794:       exp = self.exponent - other.exponent - shift
1795:       if shift >= 0
1796:         coeff, remainder = (self.coefficient*num_class.int_radix_power(shift)).divmod(other.coefficient)
1797:       else
1798:         coeff, remainder = self.coefficient.divmod(other.coefficient*num_class.int_radix_power(-shift))
1799:       end
1800:       if remainder != 0
1801:         return context.exception(Inexact) if context.exact?
1802:         # result is not exact; adjust to ensure correct rounding
1803:         if num_class.radix == 10
1804:           # perform 05up rounding so the the final rounding will be correct
1805:           coeff += 1 if (coeff%5) == 0
1806:         else
1807:           # since we will round to less digits and there is a remainder, we just need
1808:           # to append some nonzero digit; but we must avoid producing a tie (adding a single
1809:           # digit whose value is radix/2), so we append two digits, 01, that will be rounded away
1810:           coeff = num_class.int_mult_radix_power(coeff, 2) + 1
1811:           exp -= 2
1812:         end
1813:       else
1814:         # result is exact; get as close to idaal exponent as possible
1815:         ideal_exp = self.exponent - other.exponent
1816:         while (exp < ideal_exp) && ((coeff % num_class.radix)==0)
1817:           coeff /= num_class.radix
1818:           exp += 1
1819:         end
1820:       end
1821: 
1822:     end
1823:     return Num(resultsign, coeff, exp)._fix(context)
1824: 
1825:   end
divide_int(other, context=nil) click to toggle source

General Decimal Arithmetic Specification integer division: (x/y).truncate

      # File lib/flt/num.rb, line 2078
2078:   def divide_int(other, context=nil)
2079:     context = define_context(context)
2080:     other = _convert(other)
2081: 
2082:     ans = _check_nans(context,other)
2083:     return ans if ans
2084: 
2085:     sign = self.sign * other.sign
2086: 
2087:     if self.infinite?
2088:       return context.exception(InvalidOperation, 'INF // INF') if other.infinite?
2089:       return num_class.infinity(sign)
2090:     end
2091: 
2092:     if other.zero?
2093:       if self.zero?
2094:         return context.exception(DivisionUndefined, '0 // 0')
2095:       else
2096:         return context.exception(DivisionByZero, 'x // 0', sign)
2097:       end
2098:     end
2099:     return self._divide_truncate(other, context).first
2100:   end
divmod(other, context=nil) click to toggle source

Ruby-style integer division and modulo: (x/y).floor, x - y*(x/y).floor

      # File lib/flt/num.rb, line 2044
2044:   def divmod(other, context=nil)
2045:     context = define_context(context)
2046:     other = _convert(other)
2047: 
2048:     ans = _check_nans(context,other)
2049:     return [ans,ans] if ans
2050: 
2051:     sign = self.sign * other.sign
2052: 
2053:     if self.infinite?
2054:       if other.infinite?
2055:         ans = context.exception(InvalidOperation, 'divmod(INF,INF)')
2056:         return [ans,ans]
2057:       else
2058:         return [num_class.infinity(sign), context.exception(InvalidOperation, 'INF % x')]
2059:       end
2060:     end
2061: 
2062:     if other.zero?
2063:       if self.zero?
2064:         ans = context.exception(DivisionUndefined, 'divmod(0,0)')
2065:         return [ans,ans]
2066:       else
2067:         return [context.exception(DivisionByZero, 'x // 0', sign),
2068:                  context.exception(InvalidOperation, 'x % 0')]
2069:       end
2070:     end
2071: 
2072:     quotient, remainder = self._divide_floor(other, context)
2073:     return [quotient, remainder._fix(context)]
2074:   end
divrem(other, context=nil) click to toggle source

General Decimal Arithmetic Specification integer division and remainder:

 (x/y).truncate, x - y*(x/y).truncate
      # File lib/flt/num.rb, line 2011
2011:   def divrem(other, context=nil)
2012:     context = define_context(context)
2013:     other = _convert(other)
2014: 
2015:     ans = _check_nans(context,other)
2016:     return [ans,ans] if ans
2017: 
2018:     sign = self.sign * other.sign
2019: 
2020:     if self.infinite?
2021:       if other.infinite?
2022:         ans = context.exception(InvalidOperation, 'divmod(INF,INF)')
2023:         return [ans,ans]
2024:       else
2025:         return [num_class.infinity(sign), context.exception(InvalidOperation, 'INF % x')]
2026:       end
2027:     end
2028: 
2029:     if other.zero?
2030:       if self.zero?
2031:         ans = context.exception(DivisionUndefined, 'divmod(0,0)')
2032:         return [ans,ans]
2033:       else
2034:         return [context.exception(DivisionByZero, 'x // 0', sign),
2035:                  context.exception(InvalidOperation, 'x % 0')]
2036:       end
2037:     end
2038: 
2039:     quotient, remainder = self._divide_truncate(other, context)
2040:     return [quotient, remainder._fix(context)]
2041:   end
eql?(other) click to toggle source
      # File lib/flt/num.rb, line 2650
2650:   def eql?(other)
2651:     return false unless other.is_a?(num_class)
2652:     reduce.split == other.reduce.split
2653:   end
even?() click to toggle source

returns true if is an even integer

      # File lib/flt/num.rb, line 2784
2784:   def even?
2785:     # integral? && ((to_i%2)==0)
2786:     if finite?
2787:       if @exp>0 || @coeff==0
2788:         true
2789:       else
2790:         if @exp <= -number_of_digits
2791:           false
2792:         else
2793:           m = num_class.int_radix_power(-@exp)
2794:           if (@coeff % m) == 0
2795:             # ((@coeff / m) % 2) == 0
2796:             ((@coeff / m) & 1) == 0
2797:           else
2798:             false
2799:           end
2800:         end
2801:       end
2802:     else
2803:       false
2804:     end
2805:   end
exp(context=nil) click to toggle source

Exponential function

      # File lib/flt/num.rb, line 2329
2329:   def exp(context=nil)
2330:     context = num_class.define_context(context)
2331: 
2332:     # exp(NaN) = NaN
2333:     ans = _check_nans(context)
2334:     return ans if ans
2335: 
2336:     # exp(-Infinity) = 0
2337:     return num_class.zero if self.infinite? && (self.sign == 1)
2338: 
2339:     # exp(0) = 1
2340:     return Num(1) if self.zero?
2341: 
2342:     # exp(Infinity) = Infinity
2343:     return Num(self) if self.infinite?
2344: 
2345:     # the result is now guaranteed to be inexact (the true
2346:     # mathematical result is transcendental). There's no need to
2347:     # raise Rounded and Inexact here---they'll always be raised as
2348:     # a result of the call to _fix.
2349:     return context.exception(Inexact, 'Inexact exp') if context.exact?
2350:     p = context.precision
2351:     adj = self.adjusted_exponent
2352: 
2353:     if self.sign == 1 and adj > _number_of_digits((context.emax+1)*3)
2354:       # overflow
2355:       ans = Num(1, 1, context.emax+1)
2356:     elsif self.sign == 1 and adj > _number_of_digits((-context.etiny+1)*3)
2357:       # underflow to 0
2358:       ans = Num(1, 1, context.etiny-1)
2359:     elsif self.sign == 1 and adj < -p
2360:       # p+1 digits; final round will raise correct flags
2361:       ans = Num(1, num_clas.int_radix_power(p)+1, -p)
2362:     elsif self.sign == 1 and adj < -p-1
2363:       # p+1 digits; final round will raise correct flags
2364:       ans = Num(1, num_clas.int_radix_power(p+1)-1, -p-1)
2365:     else
2366:       # general case
2367:       x_sign = self.sign
2368:       x = self.copy_sign(1)
2369:       i, lasts, s, fact, num = 0, 0, 1, 1, 1
2370:       elim = [context.emax, -context.emin, 10000].max
2371:       xprec = num_class.radix==10 ? 3 : 4
2372:       num_class.local_context(context, :extra_precision=>xprec, :rounding=>:half_even, :elimit=>elim) do
2373:         while s != lasts
2374:           lasts = s
2375:           i += 1
2376:           fact *= i
2377:           num *= x
2378:           s += num / fact
2379:         end
2380:         s = num_class.Num(1)/s if x_sign<0
2381:       end
2382:       ans = s
2383:     end
2384: 
2385:     # at this stage, ans should round correctly with *any*
2386:     # rounding mode, not just with ROUND_HALF_EVEN
2387:     num_class.context(context, :rounding=>:half_even) do |local_context|
2388:       ans = ans._fix(local_context)
2389:       context.flags = local_context.flags
2390:     end
2391: 
2392:     return ans
2393:   end
exponent() click to toggle source

Exponent of the significand as an integer.

      # File lib/flt/num.rb, line 2721
2721:   def exponent
2722:     @exp
2723:   end
finite?() click to toggle source

Returns whether the number is finite

      # File lib/flt/num.rb, line 1537
1537:   def finite?
1538:     !special?
1539:   end
floor(opt={}) click to toggle source

General floor operation (as for Float) with same options for precision as Flt::Num#round()

      # File lib/flt/num.rb, line 2973
2973:   def floor(opt={})
2974:     opt[:rounding] = :floor
2975:     round opt
2976:   end
fma(other, third, context=nil) click to toggle source

Fused multiply-add.

Computes (self*other+third) with no rounding of the intermediate product self*other.

      # File lib/flt/num.rb, line 2988
2988:   def fma(other, third, context=nil)
2989:     context =define_context(context)
2990:     other = _convert(other)
2991:     third = _convert(third)
2992:     if self.special? || other.special?
2993:       return context.exception(InvalidOperation, 'sNaN', self) if self.snan?
2994:       return context.exception(InvalidOperation, 'sNaN', other) if other.snan?
2995:       if self.nan?
2996:         product = self
2997:       elsif other.nan?
2998:         product = other
2999:       elsif self.infinite?
3000:         return context.exception(InvalidOperation, 'INF * 0 in fma') if other.zero?
3001:         product = num_class.infinity(self.sign*other.sign)
3002:       elsif other.infinite?
3003:         return context.exception(InvalidOperation, '0 * INF  in fma') if self.zero?
3004:         product = num_class.infinity(self.sign*other.sign)
3005:       end
3006:     else
3007:       product = Num(self.sign*other.sign,self.coefficient*other.coefficient, self.exponent+other.exponent)
3008:     end
3009:     return product.add(third, context)
3010:   end
fraction_part() click to toggle source

Fraction part (as a Num)

      # File lib/flt/num.rb, line 2734
2734:   def fraction_part
2735:     ans = _check_nans
2736:     return ans if ans
2737:     self - self.integer_part
2738:   end
fractional_exponent() click to toggle source

Exponent as though the significand were a fraction (the decimal point before its first digit)

      # File lib/flt/num.rb, line 2684
2684:   def fractional_exponent
2685:     scientific_exponent + 1
2686:   end
hash() click to toggle source
      # File lib/flt/num.rb, line 2646
2646:   def hash
2647:     ([num_class]+reduce.split).hash # TODO: optimize
2648:   end
infinite?() click to toggle source

Returns whether the number is infinite

      # File lib/flt/num.rb, line 1532
1532:   def infinite?
1533:     @exp == :inf
1534:   end
inspect() click to toggle source
      # File lib/flt/num.rb, line 2577
2577:   def inspect
2578:     class_name = num_class.to_s.split('::').last
2579:     if $DEBUG
2580:       "#{class_name}('#{self}') [coeff:#{@coeff.inspect} exp:#{@exp.inspect} s:#{@sign.inspect} radix:#{num_class.radix}]"
2581:     else
2582:       "#{class_name}('#{self}')"
2583:     end
2584:   end
integer_part() click to toggle source

Integer part (as a Num)

      # File lib/flt/num.rb, line 2726
2726:   def integer_part
2727:     ans = _check_nans
2728:     return ans if ans
2729:     return_as_num = {:places=>0}
2730:     self.sign < 0 ? self.ceil(return_as_num) : self.floor(return_as_num)
2731:   end
integral?() click to toggle source

Returns true if the value is an integer

      # File lib/flt/num.rb, line 2766
2766:   def integral?
2767:     if finite?
2768:       if @exp>=0 || @coeff==0
2769:         true
2770:       else
2771:         if @exp <= -number_of_digits
2772:           false
2773:         else
2774:           m = num_class.int_radix_power(-@exp)
2775:           (@coeff % m) == 0
2776:         end
2777:       end
2778:     else
2779:       false
2780:     end
2781:   end
integral_exponent() click to toggle source

Exponent of the significand as an integer. Synonym of exponent

      # File lib/flt/num.rb, line 2705
2705:   def integral_exponent
2706:     # fractional_exponent - number_of_digits
2707:     @exp
2708:   end
integral_significand() click to toggle source

Significand as an integer, unsigned. Synonym of coefficient

      # File lib/flt/num.rb, line 2700
2700:   def integral_significand
2701:     @coeff
2702:   end
ln(context=nil) click to toggle source

Returns the natural (base e) logarithm

      # File lib/flt/num.rb, line 2396
2396:   def ln(context=nil)
2397:     context = num_class.define_context(context)
2398: 
2399:     # ln(NaN) = NaN
2400:     ans = _check_nans(context)
2401:     return ans if ans
2402: 
2403:     # ln(0.0) == -Infinity
2404:     return num_class.infinity(1) if self.zero?
2405: 
2406:     # ln(Infinity) = Infinity
2407:     return num_class.infinity if self.infinite? && self.sign == 1
2408: 
2409:     # ln(1.0) == 0.0
2410:     return num_class.zero if self == Num(1)
2411: 
2412:     # ln(negative) raises InvalidOperation
2413:     return context.exception(InvalidOperation, 'ln of a negative value') if self.sign==1
2414: 
2415:     # result is irrational, so necessarily inexact
2416:     return context.exception(Inexact, 'Inexact exp') if context.exact?
2417: 
2418:     elim = [context.emax, -context.emin, 10000].max
2419:     xprec = num_class.radix==10 ? 3 : 4
2420:     num_class.local_context(context, :extra_precision=>xprec, :rounding=>:half_even, :elimit=>elim) do
2421: 
2422:       one = num_class.Num(1)
2423: 
2424:       x = self
2425:       if (expo = x.adjusted_exponent)<1 || expo>=2
2426:         x = x.scaleb(-expo)
2427:       else
2428:         expo = nil
2429:       end
2430: 
2431:       x = (x-one)/(x+one)
2432:       x2 = x*x
2433:       ans = x
2434:       d = ans
2435:       i = one
2436:       last_ans = nil
2437:       while ans != last_ans
2438:         last_ans = ans
2439:         x = x2*x
2440:         i += 2
2441:         d = x/i
2442:         ans += d
2443:       end
2444:       ans *= 2
2445:       if expo
2446:         ans += num_class.Num(num_class.radix).ln*expo
2447:       end
2448:     end
2449: 
2450:     num_class.context(context, :rounding=>:half_even) do |local_context|
2451:       ans = ans._fix(local_context)
2452:       context.flags = local_context.flags
2453:     end
2454:     return ans
2455:   end
log(b=nil, context=nil) click to toggle source

Ruby-style logarithm of arbitrary base, e (natural base) by default

      # File lib/flt/num.rb, line 2458
2458:   def log(b=nil, context=nil)
2459:     if b.nil?
2460:       self.ln(context)
2461:     elsif b==10
2462:       self.log10(context)
2463:     elsif b==2
2464:       self.log2(context)
2465:     else
2466:       context = num_class.define_context(context)
2467:       +num_class.context(:extra_precision=>3){self.ln(context)/num_class[b].ln(context)}
2468:     end
2469:   end
log10(context=nil) click to toggle source

Returns the base 10 logarithm

      # File lib/flt/num.rb, line 2472
2472:   def log10(context=nil)
2473:     context = num_class.define_context(context)
2474:     num_class.context(:extra_precision=>3){self.ln/num_class.Num(10).ln}
2475:   end
log2(context=nil) click to toggle source

Returns the base 2 logarithm

      # File lib/flt/num.rb, line 2478
2478:   def log2(context=nil)
2479:     context = num_class.define_context(context)
2480:     num_class.context(context, :extra_precision=>3){self.ln()/num_class.Num(2).ln}
2481:   end
logb(context=nil) click to toggle source

Returns the exponent of the magnitude of the most significant digit.

The result is the integer which is the exponent of the magnitude of the most significant digit of the number (as though it were truncated to a single digit while maintaining the value of that digit and without limiting the resulting exponent).

      # File lib/flt/num.rb, line 2297
2297:   def logb(context=nil)
2298:     context = define_context(context)
2299:     ans = _check_nans(context)
2300:     return ans if ans
2301:     return num_class.infinity if infinite?
2302:     return context.exception(DivisionByZero,'logb(0)',1) if zero?
2303:     Num(adjusted_exponent)
2304:   end
minus(context=nil) click to toggle source

Unary prefix minus operator

      # File lib/flt/num.rb, line 1905
1905:   def minus(context=nil)
1906:     _neg(context)
1907:   end
modulo(other, context=nil) click to toggle source

Ruby-style modulo: x - y*div(x,y)

      # File lib/flt/num.rb, line 2129
2129:   def modulo(other, context=nil)
2130:     context = define_context(context)
2131:     other = _convert(other)
2132: 
2133:     ans = _check_nans(context,other)
2134:     return ans if ans
2135: 
2136:     #sign = self.sign * other.sign
2137: 
2138:     if self.infinite?
2139:       return context.exception(InvalidOperation, 'INF % x')
2140:     elsif other.zero?
2141:       if self.zero?
2142:         return context.exception(DivisionUndefined, '0 % 0')
2143:       else
2144:         return context.exception(InvalidOperation, 'x % 0')
2145:       end
2146:     end
2147: 
2148:     return self._divide_floor(other, context).last._fix(context)
2149:   end
multiply(other, context=nil) click to toggle source

Multiplication

      # File lib/flt/num.rb, line 1736
1736:   def multiply(other, context=nil)
1737:     context = define_context(context)
1738:     other = _convert(other)
1739:     resultsign = self.sign * other.sign
1740:     if self.special? || other.special?
1741:       ans = _check_nans(context,other)
1742:       return ans if ans
1743: 
1744:       if self.infinite?
1745:         return context.exception(InvalidOperation,"(+-)INF * 0") if other.zero?
1746:         return num_class.infinity(resultsign)
1747:       end
1748:       if other.infinite?
1749:         return context.exception(InvalidOperation,"0 * (+-)INF") if self.zero?
1750:         return num_class.infinity(resultsign)
1751:       end
1752:     end
1753: 
1754:     resultexp = self.exponent + other.exponent
1755: 
1756:     return Num(resultsign, 0, resultexp)._fix(context) if self.zero? || other.zero?
1757:     #return Num(resultsign, other.coefficient, resultexp)._fix(context) if self.coefficient==1
1758:     #return Num(resultsign, self.coefficient, resultexp)._fix(context) if other.coefficient==1
1759: 
1760:     return Num(resultsign, other.coefficient*self.coefficient, resultexp)._fix(context)
1761: 
1762:   end
nan?() click to toggle source

Returns whether the number is not actualy one (NaN, not a number).

      # File lib/flt/num.rb, line 1517
1517:   def nan?
1518:     @exp==:nan || @exp==:snan
1519:   end
next_minus(context=nil) click to toggle source

Largest representable number smaller than itself

      # File lib/flt/num.rb, line 1910
1910:   def next_minus(context=nil)
1911:     context = define_context(context)
1912:     if special?
1913:       ans = _check_nans(context)
1914:       return ans if ans
1915:       if infinite?
1916:         return Num(self) if @sign == 1
1917:         # @sign == +1
1918:         if context.exact?
1919:            return context.exception(InvalidOperation, 'Exact +INF next minus')
1920:         else
1921:           return Num(1, context.maximum_coefficient, context.etop)
1922:         end
1923:       end
1924:     end
1925: 
1926:     return context.exception(InvalidOperation, 'Exact next minus') if context.exact?
1927: 
1928:     result = nil
1929:     num_class.local_context(context) do |local|
1930:       local.rounding = :floor
1931:       local.ignore_all_flags
1932:       result = self._fix(local)
1933:       if result == self
1934:         result = self - Num(1, 1, local.etiny-1)
1935:       end
1936:     end
1937:     result
1938:   end
next_plus(context=nil) click to toggle source

Smallest representable number larger than itself

      # File lib/flt/num.rb, line 1941
1941:   def next_plus(context=nil)
1942:     context = define_context(context)
1943: 
1944:     if special?
1945:       ans = _check_nans(context)
1946:       return ans if ans
1947:       if infinite?
1948:         return Num(self) if @sign == 1
1949:         # @sign == -1
1950:         if context.exact?
1951:            return context.exception(InvalidOperation, 'Exact -INF next plus')
1952:         else
1953:           return Num(1, context.maximum_coefficient, context.etop)
1954:         end
1955:       end
1956:     end
1957: 
1958:     return context.exception(InvalidOperation, 'Exact next plus') if context.exact?
1959: 
1960:     result = nil
1961:     num_class.local_context(context) do |local|
1962:       local.rounding = :ceiling
1963:       local.ignore_all_flags
1964:       result = self._fix(local)
1965:       if result == self
1966:         result = self + Num(1, 1, local.etiny-1)
1967:       end
1968:     end
1969:     result
1970: 
1971:   end
next_toward(other, context=nil) click to toggle source

Returns the number closest to self, in the direction towards other.

      # File lib/flt/num.rb, line 1974
1974:   def next_toward(other, context=nil)
1975:     context = define_context(context)
1976:     other = _convert(other)
1977:     ans = _check_nans(context,other)
1978:     return ans if ans
1979: 
1980:     return context.exception(InvalidOperation, 'Exact next_toward') if context.exact?
1981: 
1982:     comparison = self <=> other
1983:     return self.copy_sign(other) if comparison == 0
1984: 
1985:     if comparison == 1
1986:       result = self.next_plus(context)
1987:     else # comparison == 1
1988:       result = self.next_minus(context)
1989:     end
1990: 
1991:     # decide which flags to raise using value of ans
1992:     if result.infinite?
1993:       context.exception Overflow, 'Infinite result from next_toward', result.sign
1994:       context.exception Rounded
1995:       context.exception Inexact
1996:     elsif result.adjusted_exponent < context.emin
1997:       context.exception Underflow
1998:       context.exception Subnormal
1999:       context.exception Rounded
2000:       context.exception Inexact
2001:       # if precision == 1 then we don't raise Clamped for a
2002:       # result 0E-etiny.
2003:       context.exception Clamped if result.zero?
2004:     end
2005: 
2006:     result
2007:   end
nonzero?() click to toggle source

Returns whether the number not zero

      # File lib/flt/num.rb, line 1547
1547:   def nonzero?
1548:     special? || @coeff>0
1549:   end
normal?(context=nil) click to toggle source

Returns whether the number is normal

      # File lib/flt/num.rb, line 1559
1559:   def normal?(context=nil)
1560:     return false if special? || zero?
1561:     context = define_context(context)
1562:     (context.emin <= self.adjusted_exponent) &&  (self.adjusted_exponent <= context.emax)
1563:   end
normalize(context=nil) click to toggle source

Normalizes (changes quantum) so that the coefficient has precision digits, unless it is subnormal. For surnormal numbers the Subnormal flag is raised an a subnormal is returned with the smallest possible exponent.

This is different from reduce GDAS function which was formerly called normalize, and corresponds to the classic meaning of floating-point normalization.

Note that the number is also rounded (precision is reduced) if it had more precision than the context.

      # File lib/flt/num.rb, line 2271
2271:   def normalize(context=nil)
2272:     context = define_context(context)
2273:     return Num(self) if self.special? || self.zero? || context.exact?
2274:     sign, coeff, exp = self._fix(context).split
2275:     if self.subnormal?
2276:       context.exception Subnormal
2277:       if exp > context.etiny
2278:         coeff = num_class.int_mult_radix_power(coeff, exp - context.etiny)
2279:         exp = context.etiny
2280:       end
2281:     else
2282:       min_normal_coeff = context.minimum_normalized_coefficient
2283:       while coeff < min_normal_coeff
2284:         coeff = num_class.int_mult_radix_power(coeff, 1)
2285:         exp -= 1
2286:       end
2287:     end
2288:     Num(sign, coeff, exp)
2289:   end
num_class() click to toggle source
      # File lib/flt/num.rb, line 1276
1276:   def num_class
1277:     self.class
1278:   end
number_class(context=nil) click to toggle source

Classifies a number as one of ‘sNaN’, ‘NaN’, ’-Infinity’, ’-Normal’, ’-Subnormal’, ’-Zero’,

 '+Zero', '+Subnormal', '+Normal', '+Infinity'
      # File lib/flt/num.rb, line 1568
1568:   def number_class(context=nil)
1569:     return "sNaN" if snan?
1570:     return "NaN" if nan?
1571:     if infinite?
1572:       return '+Infinity' if @sign==1
1573:       return '-Infinity' # if @sign==-1
1574:     end
1575:     if zero?
1576:       return '+Zero' if @sign==1
1577:       return '-Zero' # if @sign==-1
1578:     end
1579:     define_context(context)
1580:     if subnormal?(context)
1581:       return '+Subnormal' if @sign==1
1582:       return '-Subnormal' # if @sign==-1
1583:     end
1584:     return '+Normal' if @sign==1
1585:     return '-Normal' if @sign==1
1586:   end
number_of_digits() click to toggle source

Number of digits in the significand

      # File lib/flt/num.rb, line 2689
2689:   def number_of_digits
2690:     # digits.size
2691:     @coeff.is_a?(Integer) ? @coeff.to_s(num_class.radix).size : 0
2692:   end
odd?() click to toggle source

returns true if is an odd integer

      # File lib/flt/num.rb, line 2808
2808:   def odd?
2809:     # integral? && ((to_i%2)==1)
2810:     # integral? && !even?
2811:     if finite?
2812:       if @exp>0 || @coeff==0
2813:         false
2814:       else
2815:         if @exp <= -number_of_digits
2816:           false
2817:         else
2818:           m = num_class.int_radix_power(-@exp)
2819:           if (@coeff % m) == 0
2820:             # ((@coeff / m) % 2) == 1
2821:             ((@coeff / m) & 1) == 1
2822:           else
2823:             false
2824:           end
2825:         end
2826:       end
2827:     else
2828:       false
2829:     end
2830:   end
plus(context=nil) click to toggle source

Unary prefix plus operator

      # File lib/flt/num.rb, line 1900
1900:   def plus(context=nil)
1901:     _pos(context)
1902:   end
power(other, modulo=nil, context=nil) click to toggle source

Raises to the power of x, to modulo if given.

With two arguments, compute self**other. If self is negative then other must be integral. The result will be inexact unless other is integral and the result is finite and can be expressed exactly in ‘precision’ digits.

With three arguments, compute (self**other) % modulo. For the three argument form, the following restrictions on the arguments hold:

 * all three arguments must be integral
 * other must be nonnegative
 * at least one of self or other must be nonzero
 * modulo must be nonzero and have at most 'precision' digits

The result of a.power(b, modulo) is identical to the result that would be obtained by computing (a**b) % modulo with unbounded precision, but may be computed more efficiently. It is always exact.

      # File lib/flt/num.rb, line 3092
3092:   def power(other, modulo=nil, context=nil)
3093:     if context.nil? && (modulo.kind_of?(ContextBase) || modulo.is_a?(Hash))
3094:       context = modulo
3095:       modulo = nil
3096:     end
3097: 
3098:     context = num_class.define_context(context)
3099:     other = _convert(other)
3100: 
3101:     ans = _check_nans(context, other)
3102:     return ans if ans
3103: 
3104:     # 0**0 = NaN (!), x**0 = 1 for nonzero x (including +/-Infinity)
3105:     if other.zero?
3106:       if self.zero?
3107:         return context.exception(InvalidOperation, '0 ** 0')
3108:       else
3109:         return Num(1)
3110:       end
3111:     end
3112: 
3113:     # result has sign -1 iff self.sign is -1 and other is an odd integer
3114:     result_sign = 1
3115:     _self = self
3116:     if _self.sign == 1
3117:       if other.integral?
3118:         result_sign = 1 if !other.even?
3119:       else
3120:         # -ve**noninteger = NaN
3121:         # (-0)**noninteger = 0**noninteger
3122:         unless self.zero?
3123:           return context.exception(InvalidOperation, 'x ** y with x negative and y not an integer')
3124:         end
3125:       end
3126:       # negate self, without doing any unwanted rounding
3127:       _self = self.copy_negate
3128:     end
3129: 
3130:     # 0**(+ve or Inf)= 0; 0**(-ve or -Inf) = Infinity
3131:     if _self.zero?
3132:       return (other.sign == 1) ? Num(result_sign, 0, 0) : num_class.infinity(result_sign)
3133:     end
3134: 
3135:     # Inf**(+ve or Inf) = Inf; Inf**(-ve or -Inf) = 0
3136:     if _self.infinite?
3137:       return (other.sign == 1) ? num_class.infinity(result_sign) : Num(result_sign, 0, 0)
3138:     end
3139: 
3140:     # 1**other = 1, but the choice of exponent and the flags
3141:     # depend on the exponent of self, and on whether other is a
3142:     # positive integer, a negative integer, or neither
3143:     if _self == Num(1)
3144:       return _self if context.exact?
3145:       if other.integral?
3146:         # exp = max(self._exp*max(int(other), 0),
3147:         # 1-context.prec) but evaluating int(other) directly
3148:         # is dangerous until we know other is small (other
3149:         # could be 1e999999999)
3150:         if other.sign == 1
3151:           multiplier = 0
3152:         elsif other > context.precision
3153:           multiplier = context.precision
3154:         else
3155:           multiplier = other.to_i
3156:         end
3157: 
3158:         exp = _self.exponent * multiplier
3159:         if exp < 1-context.precision
3160:           exp = 1-context.precision
3161:           context.exception Rounded
3162:         end
3163:       else
3164:         context.exception Rounded
3165:         context.exception Inexact
3166:         exp = 1-context.precision
3167:       end
3168: 
3169:       return Num(result_sign, num_class.int_radix_power(-exp), exp)
3170:     end
3171: 
3172:     # compute adjusted exponent of self
3173:     self_adj = _self.adjusted_exponent
3174: 
3175:     # self ** infinity is infinity if self > 1, 0 if self < 1
3176:     # self ** -infinity is infinity if self < 1, 0 if self > 1
3177:     if other.infinite?
3178:       if (other.sign == 1) == (self_adj < 0)
3179:         return Num(result_sign, 0, 0)
3180:       else
3181:         return num_class.infinity(result_sign)
3182:       end
3183:     end
3184: 
3185:     # from here on, the result always goes through the call
3186:     # to _fix at the end of this function.
3187:     ans = nil
3188: 
3189:     # crude test to catch cases of extreme overflow/underflow.  If
3190:     # log_radix(self)*other >= radix**bound and bound >= len(str(Emax))
3191:     # then radixs**bound >= radix**len(str(Emax)) >= Emax+1 and hence
3192:     # self**other >= radix**(Emax+1), so overflow occurs.  The test
3193:     # for underflow is similar.
3194:     bound = _self._log_radix_exp_bound + other.adjusted_exponent
3195:     if (self_adj >= 0) == (other.sign == 1)
3196:       # self > 1 and other +ve, or self < 1 and other -ve
3197:       # possibility of overflow
3198:       if bound >= _number_of_digits(context.emax)
3199:         ans = Num(result_sign, 1, context.emax+1)
3200:       end
3201:     else
3202:       # self > 1 and other -ve, or self < 1 and other +ve
3203:       # possibility of underflow to 0
3204:       etiny = context.etiny
3205:       if bound >= _number_of_digits(-etiny)
3206:         ans = Num(result_sign, 1, etiny-1)
3207:       end
3208:     end
3209: 
3210:     # try for an exact result with precision +1
3211:     if ans.nil?
3212:       if context.exact?
3213:         if other.adjusted_exponent < 100 # ???? 4 ? ...
3214:           test_precision = _self.number_of_digits*other.to_i+1
3215:         else
3216:           test_precision = _self.number_of_digits+1
3217:         end
3218:       else
3219:         test_precision = context.precision + 1
3220:       end
3221:       ans = _self._power_exact(other, test_precision)
3222:       if !ans.nil? && (result_sign == 1)
3223:         ans = Num(1, ans.coefficient, ans.exponent)
3224:       end
3225:     end
3226: 
3227:     # usual case: inexact result, x**y computed directly as exp(y*log(x))
3228:     if !ans.nil?
3229:       return ans if context.exact?
3230:     else
3231:       return context.exception(Inexact, "Inexact power") if context.exact?
3232: 
3233:       p = context.precision
3234:       xc = _self.coefficient
3235:       xe = _self.exponent
3236:       yc = other.coefficient
3237:       ye = other.exponent
3238:       yc = -yc if other.sign == 1
3239: 
3240:       # compute correctly rounded result:  start with precision +3,
3241:       # then increase precision until result is unambiguously roundable
3242:       extra = 3
3243:       coeff, exp = nil, nil
3244:       loop do
3245:         coeff, exp = _power(xc, xe, yc, ye, p+extra)
3246:         break if (coeff % (num_class.int_radix_power(_number_of_digits(coeff)-p)/2)) != 0 # base 2: (coeff % (10**(_number_of_digits(coeff)-p-1))) != 0
3247:         extra += 3
3248:       end
3249:       ans = Num(result_sign, coeff, exp)
3250:     end
3251: 
3252:     # the specification says that for non-integer other we need to
3253:     # raise Inexact, even when the result is actually exact.  In
3254:     # the same way, we need to raise Underflow here if the result
3255:     # is subnormal.  (The call to _fix will take care of raising
3256:     # Rounded and Subnormal, as usual.)
3257:     if !other.integral?
3258:       context.exception Inexact
3259:       # pad with zeros up to length context.precision+1 if necessary
3260:       if ans.number_of_digits <= context.precision
3261:         expdiff = context.precision+1 - ans.number_of_digits
3262:         ans = Num(ans.sign, num_class.int_mult_radix_power(ans.coefficient, expdiff), ans.exponent-expdiff)
3263:       end
3264:       context.exception Underflow if ans.adjusted_exponent < context.emin
3265:     end
3266: 
3267:     ans = ans % modulo if modulo
3268: 
3269:     # unlike exp, ln and log10, the power function respects the
3270:     # rounding mode; no need to use ROUND_HALF_EVEN here
3271:     ans._fix(context)
3272:   end
qnan?() click to toggle source

Returns whether the number is a quite NaN (non-signaling)

      # File lib/flt/num.rb, line 1522
1522:   def qnan?
1523:     @exp == :nan
1524:   end
quantize(exp, context=nil, watch_exp=true) click to toggle source

Quantize so its exponent is the same as that of y.

      # File lib/flt/num.rb, line 2851
2851:   def quantize(exp, context=nil, watch_exp=true)
2852:     exp = _convert(exp)
2853:     context = define_context(context)
2854:     if self.special? || exp.special?
2855:       ans = _check_nans(context, exp)
2856:       return ans if ans
2857:       if exp.infinite? || self.infinite?
2858:         return Num(self) if exp.infinite? && self.infinite?
2859:         return context.exception(InvalidOperation, 'quantize with one INF')
2860:       end
2861:     end
2862:     exp = exp.exponent
2863:     _watched_rescale(exp, context, watch_exp)
2864:   end
reduce(context=nil) click to toggle source

Reduces an operand to its simplest form by removing trailing 0s and incrementing the exponent. (formerly called normalize in GDAS)

      # File lib/flt/num.rb, line 2240
2240:   def reduce(context=nil)
2241:     context = define_context(context)
2242:     if special?
2243:       ans = _check_nans(context)
2244:       return ans if ans
2245:     end
2246:     dup = _fix(context)
2247:     return dup if dup.infinite?
2248: 
2249:     return Num(dup.sign, 0, 0) if dup.zero?
2250: 
2251:     exp_max = context.clamp? ? context.etop : context.emax
2252:     end_d = nd = dup.number_of_digits
2253:     exp = dup.exponent
2254:     coeff = dup.coefficient
2255:     dgs = dup.digits
2256:     while (dgs[end_d-1]==0) && (exp < exp_max)
2257:       exp += 1
2258:       end_d -= 1
2259:     end
2260:     return Num(dup.sign, coeff/num_class.int_radix_power(nd-end_d), exp)
2261:   end
remainder(other, context=nil) click to toggle source

General Decimal Arithmetic Specification remainder: x - y*divide_int(x,y)

      # File lib/flt/num.rb, line 2152
2152:   def remainder(other, context=nil)
2153:     context = define_context(context)
2154:     other = _convert(other)
2155: 
2156:     ans = _check_nans(context,other)
2157:     return ans if ans
2158: 
2159:     #sign = self.sign * other.sign
2160: 
2161:     if self.infinite?
2162:       return context.exception(InvalidOperation, 'INF % x')
2163:     elsif other.zero?
2164:       if self.zero?
2165:         return context.exception(DivisionUndefined, '0 % 0')
2166:       else
2167:         return context.exception(InvalidOperation, 'x % 0')
2168:       end
2169:     end
2170: 
2171:     return self._divide_truncate(other, context).last._fix(context)
2172:   end
remainder_near(other, context=nil) click to toggle source

General Decimal Arithmetic Specification remainder-near:

 x - y*round_half_even(x/y)
      # File lib/flt/num.rb, line 2176
2176:   def remainder_near(other, context=nil)
2177:     context = define_context(context)
2178:     other = _convert(other)
2179: 
2180:     ans = _check_nans(context,other)
2181:     return ans if ans
2182: 
2183:     sign = self.sign * other.sign
2184: 
2185:     if self.infinite?
2186:       return context.exception(InvalidOperation, 'remainder_near(INF,x)')
2187:     elsif other.zero?
2188:       if self.zero?
2189:         return context.exception(DivisionUndefined, 'remainder_near(0,0)')
2190:       else
2191:         return context.exception(InvalidOperation, 'remainder_near(x,0)')
2192:       end
2193:     end
2194: 
2195:     if other.infinite?
2196:       return Num(self)._fix(context)
2197:     end
2198: 
2199:     ideal_exp = [self.exponent, other.exponent].min
2200:     if self.zero?
2201:       return Num(self.sign, 0, ideal_exp)._fix(context)
2202:     end
2203: 
2204:     expdiff = self.adjusted_exponent - other.adjusted_exponent
2205:     if (expdiff >= context.precision+1) && !context.exact?
2206:       return context.exception(DivisionImpossible)
2207:     elsif expdiff <= 2
2208:       return self._rescale(ideal_exp, context.rounding)._fix(context)
2209:     end
2210: 
2211:       self_coeff = self.coefficient
2212:       other_coeff = other.coefficient
2213:       de = self.exponent - other.exponent
2214:       if de >= 0
2215:         self_coeff = num_class.int_mult_radix_power(self_coeff, de)
2216:       else
2217:         other_coeff = num_class.int_mult_radix_power(other_coeff, -de)
2218:       end
2219:       q, r = self_coeff.divmod(other_coeff)
2220:       if 2*r + (q&1) > other_coeff
2221:         r -= other_coeff
2222:         q += 1
2223:       end
2224: 
2225:       return context.exception(DivisionImpossible) if q >= num_class.int_radix_power(context.precision) && !context.exact?
2226: 
2227:       sign = self.sign
2228:       if r < 0
2229:         sign = -sign
2230:         r = -r
2231:       end
2232: 
2233:     return Num(sign, r, ideal_exp)._fix(context)
2234: 
2235:   end
rescale(exp, context=nil, watch_exp=true) click to toggle source

Rescale so that the exponent is exp, either by padding with zeros or by truncating digits.

      # File lib/flt/num.rb, line 2834
2834:   def rescale(exp, context=nil, watch_exp=true)
2835:     context = define_context(context)
2836:     exp = _convert(exp)
2837:     if self.special? || exp.special?
2838:       ans = _check_nans(context, exp)
2839:       return ans if ans
2840:       if exp.infinite? || self.infinite?
2841:         return Num(self) if exp.infinite? && self.infinite?
2842:         return context.exception(InvalidOperation, 'rescale with one INF')
2843:       end
2844:     end
2845:     return context.exception(InvalidOperation,"exponent of rescale is not integral") unless exp.integral?
2846:     exp = exp.to_i
2847:     _watched_rescale(exp, context, watch_exp)
2848:   end
round(opt={}) click to toggle source

General rounding.

With an integer argument this acts like Float#round: the parameter specifies the number of fractional digits (or digits to the left of the decimal point if negative).

Options can be passed as a Hash instead; valid options are:

  • :rounding method for rounding (see Context#new())

The precision can be specified as:

  • :places number of fractional digits as above.

  • :exponent specifies the exponent corresponding to the digit to be rounded (exponent == -places)

  • :precision or :significan_digits is the number of digits

  • :power 10^exponent, value of the digit to be rounded, should be passed as a type convertible to Num.

  • :index 0-based index of the digit to be rounded

  • :rindex right 0-based index of the digit to be rounded

The default is :places=>0 (round to integer).

Example: ways of specifiying the rounding position

  number:     1   2   3   4  .  5    6    7    8
  :places    -3  -2  -1   0     1    2    3    4
  :exponent   3   2   1   0    -1   -2   -3   -4
  :precision  1   2   3   4     5    6    7    8
  :power    1E3 1E2  10   1   0.1 1E-2 1E-3 1E-4
  :index      0   1   2   3     4    5    6    7
  :index      7   6   5   4     3    2    1    0
      # File lib/flt/num.rb, line 2935
2935:   def round(opt={})
2936:     opt = { :places=>opt } if opt.kind_of?(Integer)
2937:     r = opt[:rounding] || :half_up
2938:     as_int = false
2939:     if v=(opt[:precision] || opt[:significant_digits])
2940:       prec = v
2941:     elsif v=(opt[:places])
2942:       prec = adjusted_exponent + 1 + v
2943:     elsif v=(opt[:exponent])
2944:       prec = adjusted_exponent + 1 - v
2945:     elsif v=(opt[:power])
2946:       prec = adjusted_exponent + 1 - num_class.Num(v).adjusted_exponent
2947:     elsif v=(opt[:index])
2948:       prec = i+1
2949:     elsif v=(opt[:rindex])
2950:       prec = number_of_digits - v
2951:     else
2952:       prec = adjusted_exponent + 1
2953:       as_int = true
2954:     end
2955:     dg = number_of_digits-prec
2956:     changed = _round(r, dg)
2957:     coeff = num_class.int_div_radix_power(@coeff, dg)
2958:     exp = @exp + dg
2959:     coeff += 1 if changed==1
2960:     result = Num(@sign, coeff, exp)
2961:     return as_int ? result.to_i : result
2962:   end
same_quantum?(other) click to toggle source

Return true if has the same exponent as other.

If either operand is a special value, the following rules are used:

  • return true if both operands are infinities

  • return true if both operands are NaNs

  • otherwise, return false.

      # File lib/flt/num.rb, line 2872
2872:   def same_quantum?(other)
2873:     other = _convert(other)
2874:     if self.special? || other.special?
2875:       return (self.nan? && other.nan?) || (self.infinite? && other.infinite?)
2876:     end
2877:     return self.exponent == other.exponent
2878:   end
scaleb(other, context=nil) click to toggle source

Adds a value to the exponent.

      # File lib/flt/num.rb, line 2307
2307:   def scaleb(other, context=nil)
2308: 
2309:     context = define_context(context)
2310:     other = _convert(other)
2311:     ans = _check_nans(context, other)
2312:     return ans if ans
2313:     return context.exception(InvalidOperation) if other.infinite? || other.exponent != 0
2314:     unless context.exact?
2315:       liminf = 2 * (context.emax + context.precision)
2316:       limsup =  2 * (context.emax + context.precision)
2317:       i = other.to_i
2318:       return context.exception(InvalidOperation) if !((liminf <= i) && (i <= limsup))
2319:     end
2320:     return Num(self) if infinite?
2321:     return Num(@sign, @coeff, @exp+i)._fix(context)
2322: 
2323:   end
scientific_exponent() click to toggle source

Synonym for Num#adjusted_exponent()

      # File lib/flt/num.rb, line 2679
2679:   def scientific_exponent
2680:     adjusted_exponent
2681:   end
sign() click to toggle source

Sign of the number: +1 for plus / -1 for minus.

      # File lib/flt/num.rb, line 2711
2711:   def sign
2712:     @sign
2713:   end
snan?() click to toggle source

Returns whether the number is a signaling NaN

      # File lib/flt/num.rb, line 1527
1527:   def snan?
1528:     @exp == :snan
1529:   end
special?() click to toggle source

Returns whether the number is a special value (NaN or Infinity).

      # File lib/flt/num.rb, line 1512
1512:   def special?
1513:     @exp.instance_of?(Symbol)
1514:   end
split() click to toggle source

Returns the internal representation of the number, composed of:

  • a sign which is +1 for plus and -1 for minus

  • a coefficient (significand) which is a nonnegative integer

  • an exponent (an integer) or :inf, :nan or :snan for special values

The value of non-special numbers is sign*coefficient*10^exponent

      # File lib/flt/num.rb, line 1507
1507:   def split
1508:     [@sign, @coeff, @exp]
1509:   end
sqrt(context=nil) click to toggle source

Square root

      # File lib/flt/num.rb, line 1828
1828:   def sqrt(context=nil)
1829:     context = define_context(context)
1830:     if special?
1831:       ans = _check_nans(context)
1832:       return ans if ans
1833:       return Num(self) if infinite? && @sign==1
1834:     end
1835:     return Num(@sign, 0, @exp/2)._fix(context) if zero?
1836:     return context.exception(InvalidOperation, 'sqrt(-x), x>0') if @sign<0
1837:     prec = context.precision + 1
1838: 
1839:     # express the number in radix**2 base
1840:     e = (@exp >> 1)
1841:     if (@exp & 1)!=0
1842:       c = @coeff*num_class.radix
1843:       l = (number_of_digits >> 1) + 1
1844:     else
1845:       c = @coeff
1846:       l = (number_of_digits+1) >> 1
1847:     end
1848:     shift = prec - l
1849:     if shift >= 0
1850:       c = num_class.int_mult_radix_power(c, (shift<<1))
1851:       exact = true
1852:     else
1853:       c, remainder = c.divmod(num_class.int_radix_power((-shift)<<1))
1854:       exact = (remainder==0)
1855:     end
1856:     e -= shift
1857: 
1858:     n = num_class.int_radix_power(prec)
1859:     while true
1860:       q = c / n
1861:       break if n <= q
1862:       n = ((n + q) >> 1)
1863:     end
1864:     exact = exact && (n*n == c)
1865: 
1866:     if exact
1867:       if shift >= 0
1868:         n = num_class.int_div_radix_power(n, shift)
1869:       else
1870:         n = num_class.int_mult_radix_power(n, -shift)
1871:       end
1872:       e += shift
1873:     else
1874:       return context.exception(Inexact) if context.exact?
1875:       # result is not exact; adjust to ensure correct rounding
1876:       if num_class.radix == 10
1877:         n += 1 if (n%5)==0
1878:       else
1879:         n = num_class.int_mult_radix_power(n, 2) + 1
1880:         e -= 2
1881:       end
1882:     end
1883:     ans = Num(1,n,e)
1884:     num_class.local_context(:rounding=>:half_even) do
1885:       ans = ans._fix(context)
1886:     end
1887:     return ans
1888:   end
subnormal?(context=nil) click to toggle source

Returns whether the number is subnormal

      # File lib/flt/num.rb, line 1552
1552:   def subnormal?(context=nil)
1553:     return false if special? || zero?
1554:     context = define_context(context)
1555:     self.adjusted_exponent < context.emin
1556:   end
subtract(other, context=nil) click to toggle source

Subtraction

      # File lib/flt/num.rb, line 1723
1723:   def subtract(other, context=nil)
1724: 
1725:     context = define_context(context)
1726:     other = _convert(other)
1727: 
1728:     if self.special? || other.special?
1729:       ans = _check_nans(context,other)
1730:       return ans if ans
1731:     end
1732:     return add(other.copy_negate, context)
1733:   end
to_f() click to toggle source

Conversion to Float

      # File lib/flt/num.rb, line 2522
2522:   def to_f
2523:     if special?
2524:       if @exp==:inf
2525:         @sign/0.0
2526:       else
2527:         0.0/0.0
2528:       end
2529:     else
2530:       # to_rational.to_f
2531:       # to_s.to_f
2532:       (@sign*@coeff*(num_class.radix.to_f**@exp)).to_f
2533:     end
2534:   end
to_i() click to toggle source

Ruby-style to integer conversion.

      # File lib/flt/num.rb, line 2490
2490:   def to_i
2491:     if special?
2492:       if nan?
2493:         #return context.exception(InvalidContext)
2494:         num_class.context.exception InvalidContext
2495:         return nil
2496:       end
2497:       raise Error, "Cannot convert infinity to Integer"
2498:     end
2499:     if @exp >= 0
2500:       return @sign*num_class.int_mult_radix_power(@coeff,@exp)
2501:     else
2502:       return @sign*num_class.int_div_radix_power(@coeff,-@exp)
2503:     end
2504:   end
to_int_scale() click to toggle source

Return the value of the number as an signed integer and a scale.

      # File lib/flt/num.rb, line 2741
2741:   def to_int_scale
2742:     if special?
2743:       nil
2744:     else
2745:       [@sign*integral_significand, integral_exponent]
2746:     end
2747:   end
to_integral_exact(context=nil) click to toggle source

Rounds to a nearby integer. May raise Inexact or Rounded.

      # File lib/flt/num.rb, line 2881
2881:   def to_integral_exact(context=nil)
2882:     context = define_context(context)
2883:     if special?
2884:       ans = _check_nans(context)
2885:       return ans if ans
2886:       return Num(self)
2887:     end
2888:     return Num(self) if @exp >= 0
2889:     return Num(@sign, 0, 0) if zero?
2890:     context.exception Rounded
2891:     ans = _rescale(0, context.rounding)
2892:     context.exception Inexact if ans != self
2893:     return ans
2894:   end
to_integral_value(context=nil) click to toggle source

Rounds to a nearby integer. Doesn’t raise Inexact or Rounded.

      # File lib/flt/num.rb, line 2897
2897:   def to_integral_value(context=nil)
2898:     context = define_context(context)
2899:     if special?
2900:       ans = _check_nans(context)
2901:       return ans if ans
2902:       return Num(self)
2903:     end
2904:     return Num(self) if @exp >= 0
2905:     return _rescale(0, context.rounding)
2906:   end
to_r() click to toggle source

Conversion to Rational. Conversion of special values will raise an exception under Ruby 1.9

      # File lib/flt/num.rb, line 2508
2508:   def to_r
2509:     if special?
2510:       num = (@exp == :inf) ? @sign : 0
2511:       Rational.respond_to?(:new!) ? Rational.new!(num,0) : Rational(num,0)
2512:     else
2513:       if @exp < 0
2514:         Rational(@sign*@coeff, num_class.int_radix_power(-@exp))
2515:       else
2516:         Rational(num_class.int_mult_radix_power(@sign*@coeff,@exp), 1)
2517:       end
2518:     end
2519:   end
to_s(*args) click to toggle source

Convert to a text literal in the specified base (10 by default).

If the output base is the floating-point radix, the rendered value is the exact value of the number, showing trailing zeros up to the stored precision.

With bases different from the radix, the floating-point number is treated as an approximation with a precision of number_of_digits, representing any value within its rounding range. In that case, this method always renders that aproximated value in other base without introducing additional precision.

The resulting text numeral is such that it has as few digits as possible while preserving the original while if converted back to the same type of floating-point value with the same context precision that the original number had (number_of_digits).

To render the exact value of a Num x in a different base b this can be used

  Flt::Num.convert_exact(x, b).to_s(:base=>b)

Or, to represent a BinNum x in decimal:

  x.to_decimal_exact(:exact=>true).to_s

Options: :base output base, 10 by default

:rounding is used to override the context rounding, but it’s main use is specify :nearest as the rounding-mode, which means that the text literal will have enough digits to be converted back to self in any round-to_nearest rounding mode. Otherwise only enough digits for conversion in a specific rounding mode are produced.

:all_digits if true all significant digits are shown. A digit is considered as significant here if when used on input, cannot arbitrarily change its value and preserve the parsed value of the floating point number. Using all_digits will show trailing zeros up to the precision of the floating-point, so the output will preserve the input precision. With all_digits and the :down rounding-mod (truncation), the result will be the exact value floating-point value in the output base (if it is conmensurable with the floating-point base).

      # File lib/flt/num.rb, line 3047
3047:   def to_s(*args)
3048:     eng=false
3049:     context=nil
3050: 
3051:     # admit legacy arguments eng, context in that order
3052:     if [true,false].include?(args.first)
3053:       eng = args.shift
3054:     end
3055:     if args.first.is_a?(Num::ContextBase)
3056:       context = args.shift
3057:     end
3058:     # admit also :eng to specify the eng mode
3059:     if args.first == :eng
3060:       eng = true
3061:       args.shift
3062:     end
3063:     raise TypeError, "Invalid arguments to #{num_class}#to_s" if args.size>1 || (args.size==1 && !args.first.is_a?(Hash))
3064:     # an admit arguments through a final parameters Hash
3065:     options = args.first || {}
3066:     context = options.delete(:context) if options.has_key?(:context)
3067:     eng = options.delete(:eng) if options.has_key?(:eng)
3068: 
3069:     format(context, options.merge(:eng=>eng))
3070:   end
truncate(opt={}) click to toggle source

General truncate operation (as for Float) with same options for precision as Flt::Num#round()

      # File lib/flt/num.rb, line 2980
2980:   def truncate(opt={})
2981:     opt[:rounding] = :down
2982:     round opt
2983:   end
ulp(context = nil, mode=:low) click to toggle source

ulp (unit in the last place) according to the definition proposed by J.M. Muller in “On the definition of ulp(x)” INRIA No. 5504 If the mode parameter has the value :high the Golberg ulp is computed instead; which is different on the powers of the radix (which are the borders between areas of different ulp-magnitude)

      # File lib/flt/num.rb, line 2541
2541:   def ulp(context = nil, mode=:low)
2542:     context = define_context(context)
2543: 
2544:     return context.exception(InvalidOperation, "ulp in exact context") if context.exact?
2545: 
2546:     if self.nan?
2547:       return Num(self)
2548:     elsif self.infinite?
2549:       # The ulp here is context.maximum_finite - context.maximum_finite.next_minus
2550:       return Num(1, 1, context.etop)
2551:     elsif self.zero? || self.adjusted_exponent <= context.emin
2552:       # This is the ulp value for self.abs <= context.minimum_normal*num_class.context
2553:       # Here we use it for self.abs < context.minimum_normal*num_class.context;
2554:       #  because of the simple exponent check; the remaining cases are handled below.
2555:       return context.minimum_nonzero
2556:     else
2557:       # The next can compute the ulp value for the values that
2558:       #   self.abs > context.minimum_normal && self.abs <= context.maximum_finite
2559:       # The cases self.abs < context.minimum_normal*num_class.context have been handled above.
2560: 
2561:       # assert self.normal? && self.abs>context.minimum_nonzero
2562:       norm = self.normalize
2563:       exp = norm.integral_exponent
2564:       sig = norm.integral_significand
2565: 
2566:       # Powers of the radix, r**n, are between areas with different ulp values: r**(n-p-1) and r**(n-p)
2567:       # (p is context.precision).
2568:       # This method and the ulp definitions by Muller, Kahan and Harrison assign the smaller ulp value
2569:       # to r**n; the definition by Goldberg assigns it to the larger ulp (so ulp varies with adjusted_exponent).
2570:       # The next line selects the smaller ulp for powers of the radix:
2571:       exp -= 1 if sig == num_class.int_radix_power(context.precision-1) if mode == :low
2572: 
2573:       return Num(1, 1, exp)
2574:     end
2575:   end
zero?() click to toggle source

Returns whether the number is zero

      # File lib/flt/num.rb, line 1542
1542:   def zero?
1543:     @coeff==0 && !special?
1544:   end

Protected Instance Methods

_divide_floor(other, context) click to toggle source
      # File lib/flt/num.rb, line 3529
3529:   def _divide_floor(other, context)
3530:     context = define_context(context)
3531:     sign = self.sign * other.sign
3532:     if other.infinite?
3533:       ideal_exp = self.exponent
3534:     else
3535:       ideal_exp = [self.exponent, other.exponent].min
3536:     end
3537: 
3538:     expdiff = self.adjusted_exponent - other.adjusted_exponent
3539:     if self.zero? || other.infinite? || (expdiff <= 2)
3540:       return [Num(sign, 0, 0), _rescale(ideal_exp, context.rounding)]
3541:     end
3542:     if (expdiff <= context.precision) || context.exact?
3543:       self_coeff = self.coefficient*self.sign
3544:       other_coeff = other.coefficient*other.sign
3545:       de = self.exponent - other.exponent
3546:       if de >= 0
3547:         self_coeff = num_class.int_mult_radix_power(self_coeff, de)
3548:       else
3549:         other_coeff = num_class.int_mult_radix_power(other_coeff, -de)
3550:       end
3551:       q, r = self_coeff.divmod(other_coeff)
3552:       if r<0
3553:         r = -r
3554:         rs = 1
3555:       else
3556:         rs = 1
3557:       end
3558:       if q<0
3559:         q = -q
3560:         qs = 1
3561:       else
3562:         qs = 1
3563:       end
3564:       if (q < num_class.int_radix_power(context.precision)) || context.exact?
3565:         return [Num(qs, q, 0),Num(rs, r, ideal_exp)]
3566:       end
3567:     end
3568:     # Here the quotient is too large to be representable
3569:     ans = context.exception(DivisionImpossible, 'quotient too large in //, % or divmod')
3570:     return [ans, ans]
3571: 
3572:   end
_divide_truncate(other, context) click to toggle source
      # File lib/flt/num.rb, line 3496
3496:   def _divide_truncate(other, context)
3497:     context = define_context(context)
3498:     sign = self.sign * other.sign
3499:     if other.infinite?
3500:       ideal_exp = self.exponent
3501:     else
3502:       ideal_exp = [self.exponent, other.exponent].min
3503:     end
3504: 
3505:     expdiff = self.adjusted_exponent - other.adjusted_exponent
3506:     if self.zero? || other.infinite? || (expdiff <= 2)
3507:       return [Num(sign, 0, 0), _rescale(ideal_exp, context.rounding)]
3508:     end
3509:     if (expdiff <= context.precision) || context.exact?
3510:       self_coeff = self.coefficient
3511:       other_coeff = other.coefficient
3512:       de = self.exponent - other.exponent
3513:       if de >= 0
3514:         self_coeff = num_class.int_mult_radix_power(self_coeff, de)
3515:       else
3516:         other_coeff = num_class.int_mult_radix_power(other_coeff, -de)
3517:       end
3518:       q, r = self_coeff.divmod(other_coeff)
3519:       if (q < num_class.int_radix_power(context.precision)) || context.exact?
3520:         return [Num(sign, q, 0),Num(self.sign, r, ideal_exp)]
3521:       end
3522:     end
3523:     # Here the quotient is too large to be representable
3524:     ans = context.exception(DivisionImpossible, 'quotient too large in //, % or divmod')
3525:     return [ans, ans]
3526: 
3527:   end
_log_radix_exp_bound() click to toggle source

Compute a lower bound for the adjusted exponent of self.log10() In other words, find r such that self.log10() >= 10**r. Assumes that self is finite and positive and that self != 1.

      # File lib/flt/num.rb, line 3746
3746:   def _log_radix_exp_bound
3747:     # For x >= radix or x < 1/radix we only need a bound on the integer
3748:     # part of log_radix(self), and this comes directly from the
3749:     # exponent of x.  For 1/radix <= x <= radix we use the inequalities
3750:     # 1-1/x <= log(x) <= x-1. If x > 1 we have |log_radix(x)| >
3751:     # (1-1/x)/k > 0.  If x < 1 then |log_radix(x)| > (1-x)/k > 0
3752:     # with k = floor(log(radix)*radix**m)/radix**m (m = 3 for radix=10)
3753:     #
3754:     # The original Python cod used lexical order (having converted to strings) for (num < den) and (num < 231)
3755:     # so the results would be different e.g. for num = 9; Can this happen? What is the correct way?
3756: 
3757:     adj = self.exponent + number_of_digits - 1
3758:     return _number_of_digits(adj) - 1 if adj >= 1 # self >= radix
3759:     return _number_of_digits(1-adj)-1 if adj <= 2 # self < 1/radix
3760: 
3761:     k, m = {
3762:       10 => [231, 3],
3763:       2 => [89, 7]
3764:     }[num_class.radix]
3765:     raise InvalidOperation, "Base #{num_class.radix} not supported for _log_radix_exp_bound" if k.nil?
3766: 
3767:     c = self.coefficient
3768:     e = self.exponent
3769:     if adj == 0
3770:       # 1 < self < 10
3771:       num = (c - num_class.int_radix_power(-e))
3772:       den = (k*c)
3773:       return _number_of_digits(num) - _number_of_digits(den) - ((num < den) ? 1 : 0) + (m-1)
3774:     end
3775:     # adj == -1, 0.1 <= self < 1
3776:     num = (num_class.int_radix_power(-e)-c)
3777:     return _number_of_digits(num.to_i) + e - ((num < k) ? 1 : 0) - (m-2)
3778:   end
_power_exact(other, p) click to toggle source

Attempt to compute self**other exactly Given Decimals self and other and an integer p, attempt to compute an exact result for the power self**other, with p digits of precision. Return nil if self**other is not exactly representable in p digits.

Assumes that elimination of special cases has already been performed: self and other must both be nonspecial; self must be positive and not numerically equal to 1; other must be nonzero. For efficiency, other.exponent should not be too large, so that 10**other.exponent.abs is a feasible calculation.

      # File lib/flt/num.rb, line 3791
3791:   def _power_exact(other, p)
3792: 
3793:     # In the comments below, we write x for the value of self and
3794:     # y for the value of other.  Write x = xc*10**xe and y =
3795:     # yc*10**ye.
3796: 
3797:     # The main purpose of this method is to identify the *failure*
3798:     # of x**y to be exactly representable with as little effort as
3799:     # possible.  So we look for cheap and easy tests that
3800:     # eliminate the possibility of x**y being exact.  Only if all
3801:     # these tests are passed do we go on to actually compute x**y.
3802: 
3803:     # Here's the main idea.  First normalize both x and y.  We
3804:     # express y as a rational m/n, with m and n relatively prime
3805:     # and n>0.  Then for x**y to be exactly representable (at
3806:     # *any* precision), xc must be the nth power of a positive
3807:     # integer and xe must be divisible by n.  If m is negative
3808:     # then additionally xc must be a power of either 2 or 5, hence
3809:     # a power of 2**n or 5**n.
3810:     #
3811:     # There's a limit to how small |y| can be: if y=m/n as above
3812:     # then:
3813:     #
3814:     #  (1) if xc != 1 then for the result to be representable we
3815:     #      need xc**(1/n) >= 2, and hence also xc**|y| >= 2.  So
3816:     #      if |y| <= 1/nbits(xc) then xc < 2**nbits(xc) <=
3817:     #      2**(1/|y|), hence xc**|y| < 2 and the result is not
3818:     #      representable.
3819:     #
3820:     #  (2) if xe != 0, |xe|*(1/n) >= 1, so |xe|*|y| >= 1.  Hence if
3821:     #      |y| < 1/|xe| then the result is not representable.
3822:     #
3823:     # Note that since x is not equal to 1, at least one of (1) and
3824:     # (2) must apply.  Now |y| < 1/nbits(xc) iff |yc|*nbits(xc) <
3825:     # 10**-ye iff len(str(|yc|*nbits(xc)) <= -ye.
3826:     #
3827:     # There's also a limit to how large y can be, at least if it's
3828:     # positive: the normalized result will have coefficient xc**y,
3829:     # so if it's representable then xc**y < 10**p, and y <
3830:     # p/log10(xc).  Hence if y*log10(xc) >= p then the result is
3831:     # not exactly representable.
3832: 
3833:     # if len(str(abs(yc*xe)) <= -ye then abs(yc*xe) < 10**-ye,
3834:     # so |y| < 1/xe and the result is not representable.
3835:     # Similarly, len(str(abs(yc)*xc_bits)) <= -ye implies |y|
3836:     # < 1/nbits(xc).
3837: 
3838:     xc = self.coefficient
3839:     xe = self.exponent
3840:     while (xc % num_class.radix) == 0
3841:       xc /= num_class.radix
3842:       xe += 1
3843:     end
3844: 
3845:     yc = other.coefficient
3846:     ye = other.exponent
3847:     while (yc % num_class.radix) == 0
3848:       yc /= num_class.radix
3849:       ye += 1
3850:     end
3851: 
3852:     # case where xc == 1: result is 10**(xe*y), with xe*y
3853:     # required to be an integer
3854:     if xc == 1
3855:       if ye >= 0
3856:         exponent = xe*yc*num_class.int_radix_power(ye)
3857:       else
3858:         exponent, remainder = (xe*yc).divmod(num_class.int_radix_power(-ye))
3859:         return nil if remainder!=0
3860:       end
3861:       exponent = -exponent if other.sign == 1
3862:       # if other is a nonnegative integer, use ideal exponent
3863:       if other.integral? and (other.sign == 1)
3864:         ideal_exponent = self.exponent*other.to_i
3865:         zeros = [exponent-ideal_exponent, p-1].min
3866:       else
3867:         zeros = 0
3868:       end
3869:       return Num(1, num_class.int_radix_power(zeros), exponent-zeros)
3870:     end
3871: 
3872:     # case where y is negative: xc must be either a power
3873:     # of 2 or a power of 5.
3874:     if other.sign == 1
3875:       # TODO: detect powers of 2 or 5
3876:       return nil
3877:     end
3878: 
3879:     # now y is positive; find m and n such that y = m/n
3880:     if ye >= 0
3881:       m, n = num_class.int_mult_radix_power(yc,ye), 1
3882:     else
3883:       return nil if (xe != 0) and (_number_of_digits((yc*xe).abs) <= -ye)
3884:       xc_bits = _nbits(xc)
3885:       return nil if (xc != 1) and (_number_of_digits(yc.abs*xc_bits) <= -ye)
3886:       m, n = yc, num_class.int_radix_power(-ye)
3887:       while ((m % 2) == 0) && ((n % 2) == 0)
3888:         m /= 2
3889:         n /= 2
3890:       end
3891:       while ((m % 5) == 0) && ((n % 5) == 0)
3892:         m /= 5
3893:         n /= 5
3894:       end
3895:     end
3896: 
3897:     # compute nth root of xc*radix**xe
3898:     if n > 1
3899:       # if 1 < xc < 2**n then xc isn't an nth power
3900:       return nil if xc != 1 and xc_bits <= n
3901: 
3902:       xe, rem = xe.divmod(n)
3903:       return nil if rem != 0
3904: 
3905:       # compute nth root of xc using Newton's method
3906:       a = 1 << -(-_nbits(xc)/n) # initial estimate
3907:       q = r = nil
3908:       loop do
3909:         q, r = xc.divmod(a**(n-1))
3910:         break if a <= q
3911:         a = (a*(n-1) + q)/n
3912:       end
3913:       return nil if !((a == q) and (r == 0))
3914:       xc = a
3915:     end
3916: 
3917:     # now xc*radix**xe is the nth root of the original xc*radix**xe
3918:     # compute mth power of xc*radix**xe
3919: 
3920:     # if m > p*_log_radix_mult/_log_radix_lb(xc) then m > p/log_radix(xc),
3921:     # hence xc**m > radix**p and the result is not representable.
3922:     #return nil if (xc > 1) and (m > p*100/_log10_lb(xc))
3923:     return nil if (xc > 1) and (m > p*_log_radix_mult/_log_radix_lb(xc))
3924:     xc = xc**m
3925:     xe *= m
3926:     return nil if xc > num_class.int_radix_power(p)
3927: 
3928:     # by this point the result *is* exactly representable
3929:     # adjust the exponent to get as close as possible to the ideal
3930:     # exponent, if necessary
3931:     if other.integral? && other.sign == 1
3932:       ideal_exponent = self.exponent*other.to_i
3933:       zeros = [xe-ideal_exponent, p-_number_of_digits(xc)].min
3934:     else
3935:       zeros = 0
3936:     end
3937:     return Num(1, num_class.int_mult_radix_power(xc, zeros), xe-zeros)
3938:   end
_round(rounding, i) click to toggle source

Round to i digits using the specified method

      # File lib/flt/num.rb, line 3680
3680:   def _round(rounding, i)
3681:     send("_round_#{rounding}", i)
3682:   end
_round_ceiling(i) click to toggle source

Round up (not away from 0 if negative) to i digits

      # File lib/flt/num.rb, line 3725
3725:   def _round_ceiling(i)
3726:     sign<0 ? _round_down(i) : -_round_down(i)
3727:   end
_round_down(i) click to toggle source

Round down (toward 0, truncate) to i digits

      # File lib/flt/num.rb, line 3685
3685:   def _round_down(i)
3686:     (@coeff % num_class.int_radix_power(i))==0 ? 0 : 1
3687:   end
_round_floor(i) click to toggle source

Round down (not toward 0 if negative) to i digits

      # File lib/flt/num.rb, line 3730
3730:   def _round_floor(i)
3731:     sign>0 ? _round_down(i) : -_round_down(i)
3732:   end
_round_half_down(i) click to toggle source

Round to closest i-digit number with ties down (rounds 5 toward 0)

      # File lib/flt/num.rb, line 3695
3695:   def _round_half_down(i)
3696:     m = num_class.int_radix_power(i)
3697:     if (m>1) && ((@coeff%m) == m/2)
3698:       1
3699:     else
3700:       _round_half_up(i)
3701:     end
3702:   end
_round_half_even(i) click to toggle source

Round to closest i-digit number with ties (5) to an even digit

      # File lib/flt/num.rb, line 3715
3715:   def _round_half_even(i)
3716:     m = num_class.int_radix_power(i)
3717:     if (m>1) && ((@coeff%m) == m/2 && ((@coeff/m)%2)==0)
3718:       1
3719:     else
3720:       _round_half_up(i)
3721:     end
3722:   end
_round_half_up(i) click to toggle source

Round to closest i-digit number with ties up (rounds 5 away from 0)

      # File lib/flt/num.rb, line 3705
3705:   def _round_half_up(i)
3706:     m = num_class.int_radix_power(i)
3707:     if (m>1) && ((@coeff % m) >= m/2)
3708:       1
3709:     else
3710:       (@coeff % m)==0 ? 0 : 1
3711:     end
3712:   end
_round_up(i) click to toggle source

Round up (away from 0) to i digits

      # File lib/flt/num.rb, line 3690
3690:   def _round_up(i)
3691:     -_round_down(i)
3692:   end
_round_up05(i) click to toggle source

Round down unless digit i-1 is 0 or 5

      # File lib/flt/num.rb, line 3735
3735:   def _round_up05(i)
3736:     if ((@coeff/num_class.int_radix_power(i))%(num_class.radix/2))==0
3737:       -_round_down(i)
3738:     else
3739:       _round_down(i)
3740:     end
3741:   end
format(num_context, options={}) click to toggle source

Convert to a text literal in the specified base. If the result is converted to BinNum with the specified context rounding and the same precision that self has (self.number_of_digits), the same number will be produced.

Options: :base output base, 10 by default

:rounding is used to override the context rounding, but it’s main use is specify :nearest as the rounding-mode, which means that the text literal will have enough digits to be converted back to self in any round-to_nearest rounding mode. Otherwise only enough digits for conversion in a specific rounding mode are produced.

:all_digits if true all significant digits are shown. A digit is considere as significant here if when used on input, cannot arbitrarily change its value and preserve the parsed value of the floating point number.

:output_rounding implies :all_digits; it defines the rounding mode for the output, that will show all significant digits rounded. If it is not passed and :all_digits is true, then :rounding or the context rounding mode will be used.

Note that when :base=>10 (the default) we’re regarding the binary number x as an approximation with x.number_of_digits precision and showing that inexact value in decimal without introducing additional precision. If the exact value of the number expressed in decimal is desired (we consider the Flt an exact number), this can be done with Num.convert_exact.

      # File lib/flt/num.rb, line 3602
3602:   def format(num_context, options={})
3603:     # TODO: support options (base, all_digits, any_rounding, eng) and context options in the same hash
3604:     output_radix = options[:base] || 10
3605:     rounding = options[:rounding]
3606:     all_digits = options[:all_digits]
3607:     eng = options[:eng]
3608:     output_rounding = options[:output_rounding]
3609:     all_digits ||= output_rounding
3610: 
3611:     sgn = @sign<0 ? '-' : ''
3612:     if special?
3613:       if @exp==:inf
3614:         return "#{sgn}Infinity"
3615:       elsif @exp==:nan
3616:         return "#{sgn}NaN#{@coeff}"
3617:       else # exp==:snan
3618:         return "#{sgn}sNaN#{@coeff}"
3619:       end
3620:     end
3621: 
3622:     context = define_context(num_context)
3623:     inexact = true
3624:     rounding ||= context.rounding
3625:     output_rounding ||= rounding
3626: 
3627:     if output_radix == num_class.radix && !all_digits
3628:       # show exactly inner representation and precision
3629:       ds = @coeff.to_s(output_radix)
3630:       n_ds = ds.size
3631:       exp = integral_exponent
3632:       leftdigits = exp + n_ds
3633:     else
3634:       p = self.number_of_digits # context.precision
3635:       formatter = Flt::Support::Formatter.new(num_class.radix, context.etiny, output_radix)
3636:       formatter.format(self, @coeff, @exp, rounding, p, all_digits)
3637:       dec_pos,digits = formatter.adjusted_digits(output_rounding)
3638: 
3639:       ds = digits.map{|d| d.to_s(output_radix)}.join
3640:       n_ds = ds.size
3641:       exp = dec_pos - n_ds
3642:       leftdigits = dec_pos
3643:     end
3644: 
3645:     # TODO: DRY (this code is duplicated in num_class#format)
3646:     if exp<=0 && leftdigits>6
3647:       dotplace = leftdigits
3648:     elsif !eng
3649:       dotplace = 1
3650:     elsif @coeff==0
3651:       dotplace = (leftdigits+1)%3 - 1
3652:     else
3653:       dotplace = (leftdigits-1)%3 + 1
3654:     end
3655: 
3656:     if dotplace <=0
3657:       intpart = '0'
3658:       fracpart = '.' + '0'*(-dotplace) + ds
3659:     elsif dotplace >= n_ds
3660:       intpart = ds + '0'*(dotplace - n_ds)
3661:       fracpart = ''
3662:     else
3663:       intpart = ds[0...dotplace]
3664:       fracpart = '.' + ds[dotplace..1]
3665:     end
3666: 
3667:     if leftdigits == dotplace
3668:       e = ''
3669:     else
3670:       e = (context.capitals ? 'E' : 'e') + "%+d"%(leftdigits-dotplace)
3671:     end
3672: 
3673:     sgn + intpart + fracpart + e
3674: 
3675:   end

Private Instance Methods

Num(*args) click to toggle source

shortcut constructor:

      # File lib/flt/num.rb, line 1486
1486:   def Num(*args)
1487:     self.class.Num(*args)
1488:   end
_bin_op(op, meth, other, context=nil) click to toggle source

Used internally to define binary operators

      # File lib/flt/num.rb, line 1601
1601:   def _bin_op(op, meth, other, context=nil)
1602:     context = define_context(context)
1603:     case other
1604:       when *context.coercible_types_or_num
1605:         self.send meth, Num(other, context), context
1606:       else
1607:         x, y = other.coerce(self)
1608:         x.send op, y
1609:     end
1610:   end
define_context(*options) click to toggle source

This makes the class define context accesible to instance methods

      # File lib/flt/num.rb, line 1204
1204:   def define_context(*options)
1205:     self.class.define_context(*options)
1206:   end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.