Class: Flt::Num::ContextBase

Inherits:
Object
  • Object
show all
Defined in:
lib/flt/num.rb,
lib/flt/complex.rb

Overview

Base class for Context classes.

Derived classes will implement Floating-Point contexts for the specific floating-point types (DecNum, BinNum)

Direct Known Subclasses

BinNum::Context, DecNum::Context

Constant Summary collapse

CONDITION_MAP =
{
  #ConversionSyntax=>InvalidOperation,
  #DivisionImpossible=>InvalidOperation,
  DivisionUndefined=>InvalidOperation,
  InvalidContext=>InvalidOperation
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(num_class, *options) ⇒ ContextBase

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.

The valid options are:

  • :rounding : one of :half_even, :half_down, :half_up, :floor, :ceiling, :down, :up, :up05

  • :precision : number of digits (or 0 for exact precision)

  • :exact : if true precision is ignored and Inexact conditions are trapped,

    if :quiet it set exact precision but no trapping;
    
  • :traps : a Flags object with the exceptions to be trapped

  • :flags : a Flags object with the raised flags

  • :ignored_flags : a Flags object with the exceptions to be ignored

  • :emin, :emax : minimum and maximum adjusted exponents

  • :elimit : the exponent limits can also be defined by a single value; if positive it is taken as emax and emin=1-emax; otherwiae it is taken as emin and emax=1-emin. Such limits comply with IEEE 754-2008

  • :capitals : (true or false) to use capitals in text representations

  • :clamp : (true or false) enables clamping

See also the context constructor method Flt::Num.Context().



428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
# File 'lib/flt/num.rb', line 428

def initialize(num_class, *options)
  @num_class = num_class

  if options.first.kind_of?(ContextBase)
    base = options.shift
    copy_from base
  else
    @exact = false
    @rounding = @emin = @emax = nil
    @capitals = false
    @clamp = false
    @ignored_flags = Num::Flags()
    @traps = Num::Flags()
    @flags = Num::Flags()
    @coercible_type_handlers = num_class.base_coercible_types.dup
    @conversions = num_class.base_conversions.dup
    @angle = :rad # angular units: :rad (radians) / :deg (degrees) / :grad (gradians)
  end
  assign options.first

end

Instance Attribute Details

#angleObject

Returns the value of attribute angle.



513
514
515
# File 'lib/flt/num.rb', line 513

def angle
  @angle
end

#capitalsObject

Returns the value of attribute capitals.



513
514
515
# File 'lib/flt/num.rb', line 513

def capitals
  @capitals
end

#clampObject

Returns the value of attribute clamp.



513
514
515
# File 'lib/flt/num.rb', line 513

def clamp
  @clamp
end

#emaxObject

Returns the value of attribute emax.



513
514
515
# File 'lib/flt/num.rb', line 513

def emax
  @emax
end

#eminObject

Returns the value of attribute emin.



513
514
515
# File 'lib/flt/num.rb', line 513

def emin
  @emin
end

#flagsObject

Returns the value of attribute flags.



513
514
515
# File 'lib/flt/num.rb', line 513

def flags
  @flags
end

#ignored_flagsObject

Returns the value of attribute ignored_flags.



513
514
515
# File 'lib/flt/num.rb', line 513

def ignored_flags
  @ignored_flags
end

#roundingObject

Returns the value of attribute rounding.



513
514
515
# File 'lib/flt/num.rb', line 513

def rounding
  @rounding
end

#trapsObject

Returns the value of attribute traps.



513
514
515
# File 'lib/flt/num.rb', line 513

def traps
  @traps
end

Instance Method Details

#_coerce(x) ⇒ Object

Internally used to convert numeric types to DecNum (or to an array [sign,coefficient,exponent])



1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
# File 'lib/flt/num.rb', line 1088

def _coerce(x)
  c = x.class
  while c!=Object && (h=@coercible_type_handlers[c]).nil?
    c = c.superclass
  end
  if h
    h.call(x, self)
  else
    nil
  end
end

#abs(x) ⇒ Object

Absolute value of a decimal number



702
703
704
# File 'lib/flt/num.rb', line 702

def abs(x)
  _convert(x).abs(self)
end

#add(x, y) ⇒ Object

Addition of two decimal numbers



682
683
684
# File 'lib/flt/num.rb', line 682

def add(x,y)
  _convert(x).add(y,self)
end

#assign(options) ⇒ Object

Alters the contexts by assigning options from a Hash. See DecNum#new() for the valid options.



615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
# File 'lib/flt/num.rb', line 615

def assign(options)
  if options
    @rounding = options[:rounding] unless options[:rounding].nil?
    @precision = options[:precision] unless options[:precision].nil?
    @traps = DecNum::Flags(options[:traps]) unless options[:traps].nil?
    @flags = DecNum::Flags(options[:flags]) unless options[:flags].nil?
    @ignored_flags = DecNum::Flags(options[:ignored_flags]) unless options[:ignored_flags].nil?
    if elimit=options[:elimit]
      @emin, @emax = [elimit, 1-elimit].sort
    end
    @emin = options[:emin] unless options[:emin].nil?
    @emax = options[:emax] unless options[:emax].nil?
    @capitals = options[:capitals ] unless options[:capitals ].nil?
    @clamp = options[:clamp ] unless options[:clamp ].nil?
    @exact = options[:exact ] unless options[:exact ].nil?
    @angle = options[:angle ] unless options[:angle ].nil?
    update_precision
    if options[:extra_precision] && !@exact
      @precision += options[:extra_precision]
    end
  end
  self
end

#clamp?Boolean

is clamping enabled?

Returns:

  • (Boolean)


579
580
581
# File 'lib/flt/num.rb', line 579

def clamp?
  @clamp
end

#cmath(*parameters, &blk) ⇒ Object



279
280
281
282
283
284
285
286
287
288
# File 'lib/flt/complex.rb', line 279

def cmath(*parameters, &blk)
  # if ComplexContext is derived from ContextBase: return ComplexContext(self).math(*parameters, &blk)
  num_class.context(self) do
    if parameters.empty?
      Flt.ComplexContext(num_class.context).instance_eval &blk
    else
      Flt.xiComplexContext(num_class.context).instance_exec *parameters, &blk
    end
  end
end

#coefficient(x) ⇒ Object



1138
1139
1140
# File 'lib/flt/num.rb', line 1138

def coefficient(x)
  _convert(x).coefficient
end

#coercible_typesObject

Internal use: array of numeric types that be coerced to DecNum.



1078
1079
1080
# File 'lib/flt/num.rb', line 1078

def coercible_types
  @coercible_type_handlers.keys
end

#coercible_types_or_numObject

Internal use: array of numeric types that be coerced to DecNum, including DecNum



1083
1084
1085
# File 'lib/flt/num.rb', line 1083

def coercible_types_or_num
  [num_class] + coercible_types
end

#compare(x, y) ⇒ Object

Compares like <=> but returns a DecNum value.

  • -1 if x < y

  • 0 if x == b

  • +1 if x > y

  • NaN if x or y is NaN



883
884
885
# File 'lib/flt/num.rb', line 883

def compare(x,y)
  _convert(x).compare(y, self)
end

#convert_to(type, x) ⇒ Object

Convert a DecNum x to other numerical type



1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
# File 'lib/flt/num.rb', line 1113

def convert_to(type, x)
  converter = @conversions[type]
  if converter.nil?
    raise TypeError, "Undefined conversion from DecNum to #{type}."
  elsif converter.is_a?(Symbol)
    x.send converter
  else
    converter.call(x)
  end
end

#copy_abs(x) ⇒ Object

Returns a copy of x with the sign set to +



888
889
890
# File 'lib/flt/num.rb', line 888

def copy_abs(x)
  _convert(x).copy_abs
end

#copy_from(other) ⇒ Object

Copy the state from other Context object.

Raises:

  • (TypeError)


643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
# File 'lib/flt/num.rb', line 643

def copy_from(other)
  raise TypeError, "Assign #{other.num_class} context to #{self.num_class} context" if other.num_class != self.num_class
  @rounding = other.rounding
  @precision = other.precision
  @traps = other.traps.dup
  @flags = other.flags.dup
  @ignored_flags = other.ignored_flags.dup
  @emin = other.emin
  @emax = other.emax
  @capitals = other.capitals
  @clamp = other.clamp
  @exact = other.exact
  @coercible_type_handlers = other.coercible_type_handlers.dup
  @conversions = other.conversions.dup
  @angle = other.angle
end

#copy_negate(x) ⇒ Object

Returns a copy of x with the sign inverted



893
894
895
# File 'lib/flt/num.rb', line 893

def copy_negate(x)
  _convert(x).copy_negate
end

#copy_sign(x, y) ⇒ Object

Returns a copy of x with the sign of y



898
899
900
# File 'lib/flt/num.rb', line 898

def copy_sign(x,y)
  _convert(x).copy_sign(y)
end

#define_conversion_from(type, &blk) ⇒ Object

Define a numerical conversion from type to DecNum. The block that defines the conversion has two parameters: the value to be converted and the context and must return either a DecNum or [sign,coefficient,exponent]



1103
1104
1105
# File 'lib/flt/num.rb', line 1103

def define_conversion_from(type, &blk)
  @coercible_type_handlers[type] = blk
end

#define_conversion_to(type, &blk) ⇒ Object

Define a numerical conversion from DecNum to type as an instance method of DecNum



1108
1109
1110
# File 'lib/flt/num.rb', line 1108

def define_conversion_to(type, &blk)
  @conversions[type] = blk
end

#digitsObject

synonym for precision()



559
560
561
# File 'lib/flt/num.rb', line 559

def digits
  self.precision
end

#digits=(n) ⇒ Object

synonym for precision=()



564
565
566
# File 'lib/flt/num.rb', line 564

def digits=(n)
  self.precision=n
end

#div(x, y) ⇒ Object

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



835
836
837
# File 'lib/flt/num.rb', line 835

def div(x,y)
  _convert(x).div(y,self)
end

#divide(x, y) ⇒ Object

Division of two decimal numbers



697
698
699
# File 'lib/flt/num.rb', line 697

def divide(x,y)
  _convert(x).divide(y,self)
end

#divide_int(x, y) ⇒ Object

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



850
851
852
# File 'lib/flt/num.rb', line 850

def divide_int(x,y)
  _convert(x).divide_int(y,self)
end

#divmod(x, y) ⇒ Object

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



845
846
847
# File 'lib/flt/num.rb', line 845

def divmod(x,y)
  _convert(x).divmod(y,self)
end

#divrem(x, y) ⇒ Object

General Decimal Arithmetic Specification integer division and remainder:

(x/y).truncate, x - y*(x/y).truncate


867
868
869
# File 'lib/flt/num.rb', line 867

def divrem(x,y)
  _convert(x).divrem(y,self)
end

#dupObject



660
661
662
# File 'lib/flt/num.rb', line 660

def dup
  self.class.new(self)
end

#elimit=(e) ⇒ Object

Set the exponent limits, according to IEEE 754-2008 if e > 0 it is taken as emax and emin=1-emax if e < 0 it is taken as emin and emax=1-emin



554
555
556
# File 'lib/flt/num.rb', line 554

def elimit=(e)
  @emin, @emax = [e, 1-e].sort
end

#epsilon(sign = +1) ⇒ Object

This is the difference between 1 and the smallest DecNum value greater than 1: (DecNum(1).next_plus - DecNum(1))



999
1000
1001
1002
# File 'lib/flt/num.rb', line 999

def epsilon(sign=+1)
  return exception(InvalidOperation, "Exact context epsilon") if exact?
  Num(sign, 1, 1-precision)
end

#etinyObject

‘tiny’ exponent (emin - precision + 1) is the minimum valid value for the (integral) exponent



541
542
543
# File 'lib/flt/num.rb', line 541

def etiny
  emin - precision + 1
end

#etopObject

top exponent (emax - precision + 1) is the maximum valid value for the (integral) exponent



547
548
549
# File 'lib/flt/num.rb', line 547

def etop
  emax - precision + 1
end

#eval(&blk) ⇒ Object

Evaluate a block under a context (set up the context as a local context)

When we have a context object we can use this instead of using the context method of the numeric class, e.g.:

DecNum.context(context) { ... }

This saves verbosity, specially when numeric class is not fixed, in which case we would have to write:

context.num_class.context(context) { ... }

With this method, we simply write:

context.eval { ... }


460
461
462
463
# File 'lib/flt/num.rb', line 460

def eval(&blk)
  # TODO: consider other names for this method; use ? apply ? local ? with ?
  num_class.context(self, &blk)
end

#exactObject

Returns true if the precision is exact



605
606
607
# File 'lib/flt/num.rb', line 605

def exact
  @exact
end

#exact=(v) ⇒ Object

Enables or disables the exact precision



598
599
600
601
602
# File 'lib/flt/num.rb', line 598

def exact=(v)
  @exact = v
  update_precision
  v
end

#exact?Boolean

Returns true if the precision is exact

Returns:

  • (Boolean)


610
611
612
# File 'lib/flt/num.rb', line 610

def exact?
  @exact
end

#exception(cond, msg = '', *params) ⇒ Object

Raises a flag (unless it is being ignores) and raises and exceptioin if the trap for it is enabled.

Raises:

  • (err.new(*params))


673
674
675
676
677
678
679
# File 'lib/flt/num.rb', line 673

def exception(cond, msg='', *params)
  err = (CONDITION_MAP[cond] || cond)
  return err.handle(self, *params) if @ignored_flags[err]
  @flags << err # @flags[err] = true
  return cond.handle(self, *params) if !@traps[err]
  raise err.new(*params), msg
end

#exp(x) ⇒ Object

Exponential function: e**x



732
733
734
# File 'lib/flt/num.rb', line 732

def exp(x)
  _convert(x).exp(self)
end

#exponent(x) ⇒ Object



1142
1143
1144
# File 'lib/flt/num.rb', line 1142

def exponent(x)
  _convert(x).exponent
end

#fma(x, y, z) ⇒ Object

Fused multiply-add.

Computes (x*y+z) with no rounding of the intermediate product x*y.



874
875
876
# File 'lib/flt/num.rb', line 874

def fma(x,y,z)
  _convert(x).fma(y,z,self)
end

#half_epsilon(sign = +1) ⇒ Object

This is the maximum relative error corresponding to 1/2 ulp:

(radix/2)*radix**(-precision) == epsilon/2

This is called “machine epsilon” in Goldberg’s “What Every Computer Scientist…”



1033
1034
1035
# File 'lib/flt/num.rb', line 1033

def half_epsilon(sign=+1)
  Num(sign, num_class.radix/2, -precision)
end

#ignore_all_flagsObject

Ignore all flags if they are raised



523
524
525
526
# File 'lib/flt/num.rb', line 523

def ignore_all_flags
  #@ignored_flags << EXCEPTIONS
  @ignored_flags.set!
end

#ignore_flags(*flags) ⇒ Object

Ignore a specified set of flags if they are raised



529
530
531
532
# File 'lib/flt/num.rb', line 529

def ignore_flags(*flags)
  #@ignored_flags << flags
  @ignored_flags.set(*flags)
end

#infinite?(x) ⇒ Boolean

Returns:

  • (Boolean)


1150
1151
1152
# File 'lib/flt/num.rb', line 1150

def infinite?(x)
  _convert(x).infinite?
end

#infinity(sign = +1) ⇒ Object

A floating-point infinite number with the specified sign



1194
1195
1196
# File 'lib/flt/num.rb', line 1194

def infinity(sign = +1)
  num_class.infinity(sign)
end

#inspectObject



1041
1042
1043
1044
1045
1046
# File 'lib/flt/num.rb', line 1041

def inspect
  class_name = self.class.to_s.split('::').last
  "<#{class_name}:\n" +
  instance_variables.map { |v| "  #{v}: #{instance_variable_get(v).inspect}"}.join("\n") +
  ">\n"
end

#int_div_radix_power(x, n) ⇒ Object

Divide by an integral power of the base: x/(radix**n) for x,n integer; returns an integer.



509
510
511
# File 'lib/flt/num.rb', line 509

def int_div_radix_power(x,n)
  @num_class.int_div_radix_power(x,n)
end

#int_mult_radix_power(x, n) ⇒ Object

Multiply by an integral power of the base: x*(radix**n) for x,n integer; returns an integer.



503
504
505
# File 'lib/flt/num.rb', line 503

def int_mult_radix_power(x,n)
  @num_class.int_mult_radix_power(x,n)
end

#int_radix_power(n) ⇒ Object

Integral power of the base: radix**n for integer n; returns an integer.



497
498
499
# File 'lib/flt/num.rb', line 497

def int_radix_power(n)
  @num_class.int_radix_power(n)
end

#ln(x) ⇒ Object

Returns the natural (base e) logarithm



737
738
739
# File 'lib/flt/num.rb', line 737

def ln(x)
  _convert(x).ln(self)
end

#log(x, base = nil) ⇒ Object

Ruby-style log function: arbitrary base logarithm which defaults to natural logarithm



742
743
744
# File 'lib/flt/num.rb', line 742

def log(x, base=nil)
  _convert(x).log(base, self)
end

#log10(x) ⇒ Object

Returns the base 10 logarithm



722
723
724
# File 'lib/flt/num.rb', line 722

def log10(x)
  _convert(x).log10(self)
end

#log2(x) ⇒ Object

Returns the base 2 logarithm



727
728
729
# File 'lib/flt/num.rb', line 727

def log2(x)
  _convert(x).log10(self)
end

#logb(x) ⇒ Object

Adjusted exponent of x returned as a DecNum value.



781
782
783
# File 'lib/flt/num.rb', line 781

def logb(x)
  _convert(x).logb(self)
end

#math(*parameters, &blk) ⇒ Object

Evalute a block under a context (set up the context as a local context) and inject the context methods (math and otherwise) into the block scope.

This allows the use of regular algebraic notations for math functions, e.g. exp(x) instead of x.exp



470
471
472
473
474
475
476
477
478
479
480
# File 'lib/flt/num.rb', line 470

def math(*parameters, &blk)
  # TODO: consider renaming this to eval
  num_class.context(self) do
    if parameters.empty?
      num_class.context.instance_eval &blk
    else
      # needs instance_exe (available in Ruby 1.9, ActiveRecord; TODO: include implementation here)
      num_class.context.instance_exec *parameters, &blk
    end
  end
end

#maximum_coefficientObject

Maximum integral significand value for numbers using this context’s precision.



1049
1050
1051
1052
1053
1054
1055
1056
# File 'lib/flt/num.rb', line 1049

def maximum_coefficient
  if exact?
    exception(InvalidOperation, 'Exact maximum coefficient')
    nil
  else
    num_class.int_radix_power(precision)-1
  end
end

#maximum_finite(sign = +1) ⇒ Object

Maximum finite number



970
971
972
973
974
975
# File 'lib/flt/num.rb', line 970

def maximum_finite(sign=+1)
  return exception(InvalidOperation, "Exact context maximum finite value") if exact?
  # equals Num(+1, 1, emax+1) - Num(+1, 1, etop)
  # equals Num.infinity.next_minus(self)
  Num(sign, num_class.int_radix_power(precision)-1, etop)
end

#maximum_nan_diagnostic_digitsObject

Maximum number of diagnostic digits in NaNs for numbers using this context’s precision.



1069
1070
1071
1072
1073
1074
1075
# File 'lib/flt/num.rb', line 1069

def maximum_nan_diagnostic_digits
  if exact?
    nil # ?
  else
    precision - (clamp ? 1 : 0)
  end
end

#maximum_subnormal(sign = +1) ⇒ Object

Maximum subnormal number



985
986
987
988
989
# File 'lib/flt/num.rb', line 985

def maximum_subnormal(sign=+1)
  return exception(InvalidOperation, "Exact context maximum subnormal value") if exact?
  # equals mininum_normal.next_minus(self)
  Num(sign, num_class.int_radix_power(precision-1)-1, etiny)
end

#minimum_nonzero(sign = +1) ⇒ Object

Minimum nonzero positive number (minimum positive subnormal)



992
993
994
995
# File 'lib/flt/num.rb', line 992

def minimum_nonzero(sign=+1)
  return exception(InvalidOperation, "Exact context minimum nonzero value") if exact?
  Num(sign, 1, etiny)
end

#minimum_normal(sign = +1) ⇒ Object

Minimum positive normal number



978
979
980
981
982
# File 'lib/flt/num.rb', line 978

def minimum_normal(sign=+1)
  return exception(InvalidOperation, "Exact context maximum normal value") if exact?
  #Num(sign, 1, emin).normalize(self)
  Num(sign, minimum_normalized_coefficient, etiny)
end

#minimum_normalized_coefficientObject

Minimum value of a normalized coefficient (normalized unit)



1059
1060
1061
1062
1063
1064
1065
1066
# File 'lib/flt/num.rb', line 1059

def minimum_normalized_coefficient
  if exact?
    exception(InvalidOperation, 'Exact maximum coefficient')
    nil
  else
    num_class.int_radix_power(precision-1)
  end
end

#minus(x) ⇒ Object

Unary prefix minus operator



712
713
714
# File 'lib/flt/num.rb', line 712

def minus(x)
  _convert(x)._neg(self)
end

#modulo(x, y) ⇒ Object

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



840
841
842
# File 'lib/flt/num.rb', line 840

def modulo(x,y)
  _convert(x).modulo(y,self)
end

#multiply(x, y) ⇒ Object

Multiplication of two decimal numbers



692
693
694
# File 'lib/flt/num.rb', line 692

def multiply(x,y)
  _convert(x).multiply(y,self)
end

#nanObject

A floating-point NaN (not a number)



1199
1200
1201
# File 'lib/flt/num.rb', line 1199

def nan
  num_class.nan
end

#nan?(x) ⇒ Boolean

Returns:

  • (Boolean)


1146
1147
1148
# File 'lib/flt/num.rb', line 1146

def nan?(x)
  _convert(x).nan?
end

#necessary_digits(b) ⇒ Object

Mininum number of base b digits necessary to store any context floating point number while being able to convert the digits back to the same exact context floating point number

To convert any floating point number to base b and be able to round the result back to the same floating point number, at least this many base b digits are needed.



1178
1179
1180
1181
1182
1183
1184
1185
1186
# File 'lib/flt/num.rb', line 1178

def necessary_digits(b)
  unless exact?
    if b == radix
      precision
    else
      (precision*log(radix, b)).ceil + 1
    end
  end
end

#next_minus(x) ⇒ Object

Returns the largest representable number smaller than x.



940
941
942
# File 'lib/flt/num.rb', line 940

def next_minus(x)
  _convert(x).next_minus(self)
end

#next_plus(x) ⇒ Object

Returns the smallest representable number larger than x.



945
946
947
# File 'lib/flt/num.rb', line 945

def next_plus(x)
  _convert(x).next_plus(self)
end

#next_toward(x, y) ⇒ Object

Returns the number closest to x, in the direction towards y.

The result is the closest representable number to x (excluding x) that is in the direction towards y, unless both have the same value. If the two operands are numerically equal, then the result is a copy of x with the sign set to be the same as the sign of y.



956
957
958
# File 'lib/flt/num.rb', line 956

def next_toward(x, y)
  _convert(x).next_toward(y, self)
end

#normal?(x) ⇒ Boolean

Is a normal number?

Returns:

  • (Boolean)


813
814
815
# File 'lib/flt/num.rb', line 813

def normal?(x)
  _convert(x).normal?(self)
end

#normalize(x) ⇒ Object

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.



776
777
778
# File 'lib/flt/num.rb', line 776

def normalize(x)
  _convert(x).normalize(self)
end

#normalized_integral_exponent(x) ⇒ Object

Exponent in relation to the significand as an integer normalized to precision digits. (minimum exponent)



794
795
796
797
# File 'lib/flt/num.rb', line 794

def normalized_integral_exponent(x)
  x = _convert(x)
  x.exponent - (precision - x.number_of_digits)
end

#normalized_integral_significand(x) ⇒ Object

Significand normalized to precision digits x == normalized_integral_significand(x) * radix**(normalized_integral_exponent)



801
802
803
804
# File 'lib/flt/num.rb', line 801

def normalized_integral_significand(x)
  x = _convert(x)
  x.coefficient*(num_class.int_radix_power(precision - x.number_of_digits))
end

#Num(*args) ⇒ Object

Constructor for the associated numeric class



488
489
490
# File 'lib/flt/num.rb', line 488

def Num(*args)
  num_class.Num(*args)
end

#num_classObject

This gives access to the numeric class (Flt::Num-derived) this context is for.



483
484
485
# File 'lib/flt/num.rb', line 483

def num_class
  @num_class
end

#number_class(x) ⇒ Object

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

'+Zero', '+Subnormal', '+Normal', '+Infinity'


825
826
827
# File 'lib/flt/num.rb', line 825

def number_class(x)
  _convert(x).number_class(self)
end

#one_halfObject

One half: 1/2



1204
1205
1206
# File 'lib/flt/num.rb', line 1204

def one_half
  num_class.one_half
end

#plus(x) ⇒ Object

Unary prefix plus operator



707
708
709
# File 'lib/flt/num.rb', line 707

def plus(x)
  _convert(x).plus(self)
end

#power(x, y, modulo = nil) ⇒ Object

Power. See DecNum#power()



717
718
719
# File 'lib/flt/num.rb', line 717

def power(x,y,modulo=nil)
  _convert(x).power(y,modulo,self)
end

#precObject

synonym for precision()



569
570
571
# File 'lib/flt/num.rb', line 569

def prec
  self.precision
end

#prec=(n) ⇒ Object

synonym for precision=()



574
575
576
# File 'lib/flt/num.rb', line 574

def prec=(n)
  self.precision = n
end

#precisionObject

Number of digits of precision



593
594
595
# File 'lib/flt/num.rb', line 593

def precision
  @precision
end

#precision=(n) ⇒ Object

Set the number of digits of precision. If 0 is set the precision turns to be exact.



585
586
587
588
589
590
# File 'lib/flt/num.rb', line 585

def precision=(n)
  @precision = n
  @exact = false
  update_precision
  n
end

#quantize(x, y, watch_exp = true) ⇒ Object

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



909
910
911
# File 'lib/flt/num.rb', line 909

def quantize(x, y, watch_exp=true)
  _convert(x).quantize(y, self, watch_exp)
end

#radixObject



492
493
494
# File 'lib/flt/num.rb', line 492

def radix
  @num_class.radix
end

#rationalize(x, tol = nil) ⇒ Object

Approximate conversion to Rational within given tolerance



1214
1215
1216
# File 'lib/flt/num.rb', line 1214

def rationalize(x, tol = nil)
  x.rationalize(tol)
end

#reduce(x) ⇒ Object

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



764
765
766
# File 'lib/flt/num.rb', line 764

def reduce(x)
  _convert(x).reduce(self)
end

#regard_flags(*flags) ⇒ Object

Stop ignoring a set of flags, if they are raised



535
536
537
# File 'lib/flt/num.rb', line 535

def regard_flags(*flags)
  @ignored_flags.clear(*flags)
end

#remainder(x, y) ⇒ Object

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



855
856
857
# File 'lib/flt/num.rb', line 855

def remainder(x,y)
  _convert(x).remainder(y,self)
end

#remainder_near(x, y) ⇒ Object

General Decimal Arithmetic Specification remainder-near

x - y*round_half_even(x/y)


861
862
863
# File 'lib/flt/num.rb', line 861

def remainder_near(x,y)
  _convert(x).remainder_near(y,self)
end

#representable_digits(b) ⇒ Object

Maximum number of base b digits that can be stored in a context floating point number and then preserved when converted back to base b.

To store a base b number in a floating point number and be able to get then back exactly the number cannot have more than these significant digits.



1163
1164
1165
1166
1167
1168
1169
1170
1171
# File 'lib/flt/num.rb', line 1163

def representable_digits(b)
  unless exact?
    if b == radix
      precision
    else
      ((precision-1)*log(radix, b)).floor
    end
  end
end

#rescale(x, exp, watch_exp = true) ⇒ Object

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



904
905
906
# File 'lib/flt/num.rb', line 904

def rescale(x, exp, watch_exp=true)
  _convert(x).rescale(exp, self, watch_exp)
end

#same_quantum?(x, y) ⇒ Boolean

Return true if x and y have the same exponent.

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.

Returns:

  • (Boolean)


919
920
921
# File 'lib/flt/num.rb', line 919

def same_quantum?(x,y)
  _convert(x).same_quantum?(y)
end

#scaleb(x, y) ⇒ Object

Adds the second value to the exponent of the first: x*(radix**y)

y must be an integer



788
789
790
# File 'lib/flt/num.rb', line 788

def scaleb(x, y)
  _convert(x).scaleb(y,self)
end

#sign(x) ⇒ Object



1134
1135
1136
# File 'lib/flt/num.rb', line 1134

def sign(x)
  _convert(x).sign
end

#split(x) ⇒ Object

Simply calls x.split; implemented to ease handling Float and BigDecimal as Nums withoug having to add methods like split to those classes.



1126
1127
1128
# File 'lib/flt/num.rb', line 1126

def split(x)
  _convert(x).split
end

#sqrt(x) ⇒ Object

Square root of a decimal number



830
831
832
# File 'lib/flt/num.rb', line 830

def sqrt(x)
  _convert(x).sqrt(self)
end

#strict_epsilon(sign = +1) ⇒ Object

The strict epsilon is the smallest value that produces something different from 1 wehen added to 1. It may be smaller than the general epsilon, because of the particular rounding rules used.



1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
# File 'lib/flt/num.rb', line 1007

def strict_epsilon(sign=+1)
  return exception(InvalidOperation, "Exact context strict epsilon") if exact?
  # assume radix is even (num_class.radix%2 == 0)
  case rounding
  when :down, :floor
    # largest epsilon: 0.0...10 (precision digits shown to the right of the decimal point)
    exp = 1-precision
    coeff = 1
  when :half_even, :half_down
    # next largest:    0.0...050...1 (+precision-1 additional digits here)
    exp = 1-2*precision
    coeff = 1 + num_class.int_radix_power(precision)/2
  when :half_up
    # next largest:    0.0...05 (precision digits shown to the right of the decimal point)
    exp = 1-2*precision
    coeff = num_class.int_radix_power(precision)/2
  when :up, :ceiling, :up05
    # smallest epsilon
    return minimum_nonzero(sign)
  end
  return Num(sign, coeff, exp)
end

#subnormal?(x) ⇒ Boolean

Is a subnormal number?

Returns:

  • (Boolean)


818
819
820
# File 'lib/flt/num.rb', line 818

def subnormal?(x)
  _convert(x).subnormal?(self)
end

#subtract(x, y) ⇒ Object

Subtraction of two decimal numbers



687
688
689
# File 'lib/flt/num.rb', line 687

def subtract(x,y)
  _convert(x).subtract(y,self)
end

#to_eng_string(x) ⇒ Object

Converts a number to a string, using engineering notation



757
758
759
# File 'lib/flt/num.rb', line 757

def to_eng_string(x)
  to_string x, true
end

#to_int_scale(x) ⇒ Object



1130
1131
1132
# File 'lib/flt/num.rb', line 1130

def to_int_scale(x)
  _convert(x).to_int_scale
end

#to_integral_exact(x) ⇒ Object

Rounds to a nearby integer.

See also: DecNum#to_integral_value(), which does exactly the same as this method except that it doesn’t raise Inexact or Rounded.



927
928
929
# File 'lib/flt/num.rb', line 927

def to_integral_exact(x)
  _convert(x).to_integral_exact(self)
end

#to_integral_value(x) ⇒ Object

Rounds to a nearby integerwithout raising inexact, rounded.

See also: DecNum#to_integral_exact(), which does exactly the same as this method except that it may raise Inexact or Rounded.



935
936
937
# File 'lib/flt/num.rb', line 935

def to_integral_value(x)
  _convert(x).to_integral_value(self)
end

#to_normalized_int_scale(x) ⇒ Object

Returns both the (signed) normalized integral significand and the corresponding exponent



807
808
809
810
# File 'lib/flt/num.rb', line 807

def to_normalized_int_scale(x)
  x = _convert(x)
  [x.sign*normalized_integral_significand(x), normalized_integral_exponent(x)]
end

#to_r(x) ⇒ Object

Exact conversion to Rational



1209
1210
1211
# File 'lib/flt/num.rb', line 1209

def to_r(x)
  x.to_r
end

#to_sObject



1037
1038
1039
# File 'lib/flt/num.rb', line 1037

def to_s
  inspect
end

#to_sci_string(x) ⇒ Object

Converts a number to a string, using scientific notation



752
753
754
# File 'lib/flt/num.rb', line 752

def to_sci_string(x)
  to_string x, false
end

#to_string(x, eng = false) ⇒ Object

Converts a number to a string



747
748
749
# File 'lib/flt/num.rb', line 747

def to_string(x, eng=false)
  _convert(x)._fix(self).to_s(eng, self)
end

#ulp(x = nil, mode = :low) ⇒ Object

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



962
963
964
965
# File 'lib/flt/num.rb', line 962

def ulp(x=nil, mode=:low)
  x ||= 1
  _convert(x).ulp(self, mode)
end

#zero(sign = +1) ⇒ Object

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



1189
1190
1191
# File 'lib/flt/num.rb', line 1189

def zero(sign = +1)
  num_class.zero(sign)
end

#zero?(x) ⇒ Boolean

Returns:

  • (Boolean)


1154
1155
1156
# File 'lib/flt/num.rb', line 1154

def zero?(x)
  _convert(x).zero?
end