Class: Flt::FormatBase

Inherits:
Object
  • Object
show all
Extended by:
Flt
Includes:
Comparable, Flt
Defined in:
lib/float-formats/classes.rb,
lib/float-formats/classes.rb

Overview

General Floating Point Format Base class

Defined Under Namespace

Classes: FltFmtConversion

Constant Summary

Constants included from Flt

APPLE, IEEE_128, IEEE_128_BE, IEEE_DEC128, IEEE_DEC32, IEEE_DEC64, IEEE_DOUBLE, IEEE_D_BE, IEEE_EXTENDED, IEEE_HALF, IEEE_H_BE, IEEE_QUAD, IEEE_Q_BE, IEEE_SINGLE, IEEE_S_BE, IEEE_X_BE, IEEE_binaryx, RPL, RPL_X

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Flt

*, +, -, -@, /, bcd2dpd, bitnot, convert_bytes, dbl_from_float, dbl_from_text, dbl_to_float, dpd2bcd, dpd_to_hexbcd, float_bin, float_dec, float_from_integral_sign_significand_exponent, float_from_integral_significand_exponent, float_shortest_dec, float_significant_dec, float_to_integral_sign_significand_exponent, float_to_integral_significand_exponent, hex_from_float, hex_to_float, hexbcd_to_dpd, sgl_from_float, sgl_from_text, sgl_to_float

Constructor Details

#initialize(*args) ⇒ FormatBase

Returns a new instance of FormatBase.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/float-formats/classes.rb', line 50

def initialize(*args)
  if (args.size == 3 || args.size==4 || args.size==2) &&
     (args.first.kind_of?(Integer) && args[1].kind_of?(Integer))
    sign,significand,exponent,normalize = args
    if normalize.nil?
      if [nil,true,false].include?(exponent)
        normalize = exponent
        exponent = significand
        significand = sign.abs
        sign = sign<0 ? -1 : +1
      end
    end
    @sign,@significand,@exponent = self.class.canonicalized(sign,significand,exponent,normalize)
  else
    v = form_class.nan
    case args.first
      when form_class
        v = args.first
        raise "Too many arguments for FormatBase constructor" if args.size>1
      when Array
        v = args.first
        raise "Too many arguments for FormatBase constructor" if args.size>1
      when FormatBase
        v = args.first.convert_to(form_class)
        raise "Too many arguments for FormatBase constructor" if args.size>1
      when String
        v = form_class.from_text(*args)
      when Bytes
        v = form_class.from_bytes(*args)
      when Bits
        v = form_class.from_bits(*args)
      when Numeric
        v = form_class.from_number(args.first)
        raise "Too many arguments for FormatBase constructor" if args.size>1
      when Symbol
        if args.first.to_s[0..3]!='from'
          args = ["from_#{args.first}".to_sym] + args[1..-1]
        end
        v = form_class.send(*args)
    end
    @sign,@significand,@exponent = v.to_a
  end
end

Class Attribute Details

.hidden_bitObject (readonly)

define format properties:

radix

Numeric base

significand_digits

Number of digits in the significand (precision)

hidden_bit

Has the format a hidden bit?

parameters

Parameters used to define the class



476
477
478
# File 'lib/float-formats/classes.rb', line 476

def hidden_bit
  @hidden_bit
end

.parametersObject (readonly)

define format properties:

radix

Numeric base

significand_digits

Number of digits in the significand (precision)

hidden_bit

Has the format a hidden bit?

parameters

Parameters used to define the class



476
477
478
# File 'lib/float-formats/classes.rb', line 476

def parameters
  @parameters
end

.radixObject (readonly)

define format properties:

radix

Numeric base

significand_digits

Number of digits in the significand (precision)

hidden_bit

Has the format a hidden bit?

parameters

Parameters used to define the class



476
477
478
# File 'lib/float-formats/classes.rb', line 476

def radix
  @radix
end

.significand_digitsObject (readonly)

define format properties:

radix

Numeric base

significand_digits

Number of digits in the significand (precision)

hidden_bit

Has the format a hidden bit?

parameters

Parameters used to define the class



476
477
478
# File 'lib/float-formats/classes.rb', line 476

def significand_digits
  @significand_digits
end

Instance Attribute Details

#exponentObject (readonly)

Returns the value of attribute exponent.



94
95
96
# File 'lib/float-formats/classes.rb', line 94

def exponent
  @exponent
end

#signObject (readonly)

Returns the value of attribute sign.



94
95
96
# File 'lib/float-formats/classes.rb', line 94

def sign
  @sign
end

#significandObject (readonly)

Returns the value of attribute significand.



94
95
96
# File 'lib/float-formats/classes.rb', line 94

def significand
  @significand
end

Class Method Details

.arithmeticObject

Set up the arithmetic environment; the arithmetic type is passed to the block.



1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
# File 'lib/float-formats/classes.rb', line 1765

def self.arithmetic
  at = arithmetic_type
  if at.ancestors.include?(Flt::Num)
    at.context(self.context) do
      yield at
    end
  else
    # Could also use Flt::Decimal with decimal_digits_necessary, decimal_max_exp(:integral_significand), ...
    yield at
  end
end

.arithmetic_typeObject

Type used internally for arithmetic operations.



1760
1761
1762
1763
# File 'lib/float-formats/classes.rb', line 1760

def self.arithmetic_type
  num_class
  # Rational
end

.bias(significand_mode = :scientific_significand) ⇒ Object

Exponent bias for excess notation exponent encoding The argument defines the interpretation of the significand and so determines the actual bias value.



642
643
644
645
646
647
648
649
650
651
# File 'lib/float-formats/classes.rb', line 642

def self.bias(significand_mode = :scientific_significand)
  case significand_mode
    when :integral_significand
      @integral_bias
    when :fractional_significand
      @fractional_bias
    when :scientific_significand
      @scientific_bias
  end
end

.canonicalized(s, m, e, normalize = nil) ⇒ Object



653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
# File 'lib/float-formats/classes.rb', line 653

def self.canonicalized(s,m,e,normalize=nil)
  #puts "s=#{s} m=#{m} e=#{e}"
  #return [s,m,e]
  normalize = @normalized if normalize.nil?
  min_exp = radix_min_exp(:integral_significand)
  e = min_exp if e==:denormal
  if m.kind_of?(Integer) && m>0 && e.kind_of?(Integer)
    while e<min_exp
      e += 1
      m /= radix # TODO: round
    end
  end
  s,m,e = normalized(s,m,e) if normalize

  if m==0 && e.kind_of?(Integer)
    e=:zero
  end
  #puts " -> s=#{s} m=#{m} e=#{e}"
  [s,m,e]
end

.contextObject



577
578
579
580
581
582
583
584
# File 'lib/float-formats/classes.rb', line 577

def self.context
  num_class::Context.new(
    precision: significand_digits,
    emin: radix_min_exp(:scientific_significand),
    emax: radix_max_exp(:scientific_significand),
    rounding:@round || :half_even
  )
end

.decimal_digits_necessaryObject

number of decimal digits necessary to unambiguosly define any floating point value



498
499
500
# File 'lib/float-formats/classes.rb', line 498

def self.decimal_digits_necessary
  (significand_digits*radix_log10).ceil+1
end

.decimal_digits_storedObject

number of decimal digits that can be stored in a floating point value and restored unaltered



494
495
496
# File 'lib/float-formats/classes.rb', line 494

def self.decimal_digits_stored
  ((significand_digits-1)*radix_log10).floor
end

.decimal_max_expObject

Maximum integer such that 10 raised to that power is in the range of the normalised floating point numbers



504
505
506
507
# File 'lib/float-formats/classes.rb', line 504

def self.decimal_max_exp
  (radix_max_exp(:fractional_significand)*radix_log10+(1-radix_power(-significand_digits))*radix_log10).floor
  #(Math.log((1-radix**(significand_digits))*radix**radix_max_exp(:fractional_significand))/Math.log(10)).floor
end

.decimal_min_expObject

Minimum negative integer such that 10 raised to that power is in the range of the normalised floating point numbers



510
511
512
# File 'lib/float-formats/classes.rb', line 510

def self.decimal_min_exp
  (radix_min_exp(:fractional_significand)*radix_log10).ceil
end

.define(params = {}) {|_self| ... } ⇒ Object

Common parameters for all floating-point formats:

:bias_mode

This defines how the significand is interpreted:

  • :fractional_significand The radix point is before the most significant digit of the significand (including a hidden bit if there’s one).

  • :scientific_significand The radix point is after the most significant digit of the significand (including a hidden bit if there’s one).

  • :integral_significand The significand is assumed to be an integer, i.e. the radix point is after the least significant digit.

:bias

Defines the exponent encoding method to be excess notation and defines the bias.

:endianness

Defines the byte endianness. One of:

  • :little_endian Least significant bytes come first. (Intel etc.)

  • :big_endian (Network order): most significant bytes come first. (Motorola, SPARC,…)

  • :little_big_endian (Middle endian) Each pair of bytes (16-bit word) has the bytes in little endian order, but the words are stored in big endian order (we assume the number of bytes is even). (PDP-11).

Yields:

  • (_self)

Yield Parameters:



357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'lib/float-formats/classes.rb', line 357

def self.define(params={})
  @parameters = params

  @normalized = params[:normalized]
  @normalized = true if @normalized.nil?
  @fields_handler = params[:fields_handler]

  @exponent_radix = params[:exponent_radix] || radix

  @zero_encoded_exp = params[:zero_encoded_exp] || 0
  @min_encoded_exp = params[:min_encoded_exp] || 0
  @denormal_encoded_exp = params[:denormal_encoded_exp]
  @gradual_underflow = params[:gradual_underflow] || (@denormal_encoded_exp ? true : false)
  if @gradual_underflow
    @denormal_encoded_exp = 0 if !@denormal_encoded_exp
    if @denormal_encoded_exp>=@min_encoded_exp
      @min_encoded_exp = @denormal_encoded_exp
      # originally, we incremented min_encoded_exp here unconditionally, but
      # now we don't if there's no hidden bit
      # (we assume the minimum exponent can be used for normalized and denormalized numbers)
      # because of this, IEEE_EXTENDED & 128 formats now specify min_encoded_exp: 1 in it's definitions
      @min_encoded_exp += 1 if @hidden_bit
    end
  end
  # Note that if there's a hidden bit and no gradual underflow, the minimum encoded exponent will only
  # be used for zero unless a parameter :min_encoded_exp (=0) is passed. In this case all numbers with
  # minimun exponent and nonzero encoded significand will have a 1-valued hidden bit. Otherwise
  # the only valid encoded significand with minimun encoded exponent is 0.
  # In case of gradual underflow, the minimum exponent implies a hidden bit value of 0
  @min_encoded_exp += 1 if @min_encoded_exp==@zero_encoded_exp && (@hidden_bit && params[:min_encoded_exp].nil?)

  @infinite_encoded_exp = params[:infinite_encoded_exp]
  @nan_encoded_exp = params[:nan_encoded_exp]

  @infinity = params[:infinity] || (@infinite_encoded_exp ? true : false)
  @max_encoded_exp = params[:max_encoded_exp] || @exponent_radix**@fields[:exponent]-1 # maximum regular exponent, encoded
  if @infinity
    @infinite_encoded_exp = @nan_encoded_exp || @max_encoded_exp if !@infinite_encoded_exp
    @max_encoded_exp = @infinite_encoded_exp - 1 if @infinite_encoded_exp.kind_of?(Integer) && @infinite_encoded_exp<=@max_encoded_exp
  end
  @nan = params[:nan] || (@nan_encoded_exp ? true : false)
  if @nan
    @nan_encoded_exp = @infinite_encoded_exp || @max_encoded_exp if !@nan_encoded_exp
    @max_encoded_exp = @nan_encoded_exp - 1 if @nan_encoded_exp.kind_of?(Integer) && @nan_encoded_exp<=@max_encoded_exp
  end

  @exponent_mode = params[:exponent_mode]
  if @exponent_mode.nil?
    if params[:bias]
      @exponent_mode = :excess
    else
      @exponent_mode = :radix_complement
    end
  end
  @exponent_digits = @fields[:exponent]

  if @exponent_mode==:excess
    @bias = params[:bias] || (@exponent_radix**(@fields[:exponent]-1)-1)
    @bias_mode = params[:bias_mode] || :scientific_significand
    @min_exp = params[:min_exp]
    @max_exp = params[:max_exp]
    case @bias_mode
      when :integral_significand
        @integral_bias = @bias
        @fractional_bias = @integral_bias-@significand_digits
        @scientific_bias = @fractional_bias+1
      when :fractional_significand
        @fractional_bias = @bias
        @integral_bias = @fractional_bias+@significand_digits
        @scientific_bias = @fractional_bias+1
        @min_exp -= @significand_digits if @min_exp
        @max_exp -= @significand_digits if @max_exp
      when :scientific_significand
        @scientific_bias = @bias
        @fractional_bias = @scientific_bias-1
        @integral_bias = @fractional_bias+@significand_digits
        @min_exp -= @significand_digits-1 if @min_exp
        @max_exp -= @significand_digits-1 if @max_exp
    end
  else
    #@bias_mode = :scientific_significand
    @min_exp = params[:min_exp] || (-(@exponent_radix**@exponent_digits)/2 + 1)
    @max_exp = params[:max_exp] || ((@exponent_radix**@exponent_digits)/2 - 1)
  end
  @endianness = params[:endianness] || :little_endian

  @min_exp = @min_encoded_exp - @integral_bias if @min_exp.nil?
  @max_exp = @max_encoded_exp - @integral_bias if @max_exp.nil?

  if @exponent_mode==:excess
    @integral_max_exp = @max_exp
    @integral_min_exp = @min_exp
    @fractional_max_exp = @max_exp+@significand_digits
    @fractional_min_exp = @min_exp+@significand_digits
    @scientific_max_exp = @max_exp+@significand_digits-1
    @scientific_min_exp = @min_exp+@significand_digits-1
  else
    @integral_max_exp = @max_exp - (@significand_digits-1)
    @integral_min_exp = @min_exp - (@significand_digits-1)
    @fractional_max_exp = @max_exp+1
    @fractional_min_exp = @min_exp+1
    @scientific_max_exp = @max_exp
    @scientific_min_exp = @min_exp
  end

  @round = params[:round] # || :half_even

  @neg_mode = params[:neg_mode] || :sign_magnitude

  yield self if block_given?

end

.endiannessObject

Endianness of the format (:little_endian, :big_endian or :little_big_endian)



630
631
632
# File 'lib/float-formats/classes.rb', line 630

def self.endianness
  @endianness
end

.epsilon(sign = +1) ⇒ Object

This is the difference between 1.0 and the smallest floating-point value greater than 1.0, radix_power(1-significand_precision)



746
747
748
749
750
751
752
753
# File 'lib/float-formats/classes.rb', line 746

def self.epsilon(sign=+1)
  s = sign
  #m = 1
  #e = 1-significand_digits
  m = minimum_normalized_integral_significand
  e = 2*(1-significand_digits)
  return_value s,m,e, false
end

.from(*args) ⇒ Object

from methods



822
823
824
# File 'lib/float-formats/classes.rb', line 822

def self.from(*args)
  new(*args)
end

.from_bits(i) ⇒ Object

Defines a floating-point number from the encoded integral value.



862
863
864
865
866
867
868
869
870
871
872
873
874
875
# File 'lib/float-formats/classes.rb', line 862

def self.from_bits(i)
  v = Bytes.from_i(i)
  if v.size<total_bytes
    fill = (0.chr*(total_bytes-v.size))
    if @endianness==:little_endian
      v << fill
    else
      v = Bytes.new(fill) + bytes
    end
  elsif v.size>total_bytes
    raise "Invalid floating point value"
  end
  from_bytes v
end

.from_bits_text(txt, base) ⇒ Object

Defines a floating-point number from a text representation of the encoded integral value in a given base. Returns a Value.



880
881
882
883
# File 'lib/float-formats/classes.rb', line 880

def self.from_bits_text(txt, base)
  i = Numerals::Format[].read(txt, type: Integer, base: base)
  from_bits i
end

.from_bytes(b) ⇒ Object



826
827
828
# File 'lib/float-formats/classes.rb', line 826

def self.from_bytes(b)
  return_value(*unpack(b))
end

.from_hex(hex) ⇒ Object



830
831
832
# File 'lib/float-formats/classes.rb', line 830

def self.from_hex(hex)
  from_bytes Bytes.from_hex(hex)
end

.from_number(v, mode = :approx) ⇒ Object



834
835
836
837
838
839
840
841
842
843
844
845
# File 'lib/float-formats/classes.rb', line 834

def self.from_number(v, mode = :approx)
  if v.is_a?(Flt::Num) && v.num_class.radix==self.radix
    self.num(v)
  else
    options = {
      type: self,
      exact_input: (mode != :approx),
      output_mode: @normalized ? :fixed : :short
    }
    Numerals::Conversions.convert(v, options)
  end
end

.from_text(txt, *args) ⇒ Object



847
848
849
850
851
852
853
854
855
# File 'lib/float-formats/classes.rb', line 847

def self.from_text(txt, *args)
  if @normalized
    fmt = Numerals::Format[exact_input: true]
  else
    fmt = Numerals::Format[:short, exact_input: false]
  end
  fmt = fmt[*args]
  fmt.read(txt, type: self)
end

.gradual_underflow?Boolean

Does the format support gradual underflow? (denormalized numbers)

Returns:

  • (Boolean)


635
636
637
# File 'lib/float-formats/classes.rb', line 635

def self.gradual_underflow?
  @gradual_underflow
end

.half_epsilon(sign = +1) ⇒ Object

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

(radix/2)*radix_power(-significand_precision) == epsilon/2

This is called “machine epsilon” in [Goldberg] TODO: use Flt::Num



789
790
791
792
793
794
795
796
797
# File 'lib/float-formats/classes.rb', line 789

def self.half_epsilon(sign=+1)
  s = sign
  m = radix/2
  e = -significand_digits
  # normalize:
    m *= minimum_normalized_integral_significand
    e -= significand_digits-1
  return_value s,m,e, false
end

.infinity(sign = +1) ⇒ Object

Floating point representation of infinity.



804
805
806
807
808
809
810
# File 'lib/float-formats/classes.rb', line 804

def self.infinity(sign=+1)
  if @infinite_encoded_exp
    return_value sign, 0, :infinity
  else
    nil
  end
end

.join(sign, significand, exponent) ⇒ Object



857
858
859
# File 'lib/float-formats/classes.rb', line 857

def self.join(sign,significand,exponent)
  self.new sign,significand,exponent
end

.max_value(sign = +1) ⇒ Object

Greatest finite normalized floating point number in the representation. It can be made negative by passing the sign (a so this would be the smallest finite number).



716
717
718
719
720
721
# File 'lib/float-formats/classes.rb', line 716

def self.max_value(sign=+1)
  s = sign
  m = maximum_integral_significand
  e = radix_max_exp(:integral_significand)
  return_value s,m,e, false
end

.maximum_integral_significandObject



542
543
544
# File 'lib/float-formats/classes.rb', line 542

def self.maximum_integral_significand
  radix_power(significand_digits)-1
end

.min_normalized_value(sign = +1) ⇒ Object

Smallest normalized floating point number greater than zero in the representation. It can be made negative by passing the sign.



724
725
726
727
728
729
730
# File 'lib/float-formats/classes.rb', line 724

def self.min_normalized_value(sign=+1)
  s = sign
  m = minimum_normalized_integral_significand
  e = radix_min_exp(:integral_significand)
  m += 1 if @hidden_bit && (@min_encoded_exp==@zero_encoded_exp)
  return_value s,m,e, true
end

.min_value(sign = +1) ⇒ Object

Smallest floating point number greater than zero in the representation, including denormalized values if the representation supports it. It can be made negative by passing the sign.



734
735
736
737
738
739
740
741
742
743
# File 'lib/float-formats/classes.rb', line 734

def self.min_value(sign=+1)
  if @denormal_encoded_exp
    s = sign
    m = 1
    e = :denormal
    return_value s,m,e, false
  else
    min_normalized_value(sign)
  end
end

.minimum_normalized_integral_significandObject



539
540
541
# File 'lib/float-formats/classes.rb', line 539

def self.minimum_normalized_integral_significand
  radix_power(significand_digits-1)
end

.minus_sign_valueObject

Stored (integral) value for the minus sign



514
515
516
# File 'lib/float-formats/classes.rb', line 514

def self.minus_sign_value
  (-1) % radix
end

.nanObject

Floating point representation of Not-a-Number.



812
813
814
815
816
817
818
# File 'lib/float-formats/classes.rb', line 812

def self.nan
  if @nan_encoded_exp
    return_value(+1, 0, :nan)
  else
    nil
  end
end

.num(x) ⇒ Object

def to_num

# num_class = Flt::Num[form_class.radix]
num_class = self.class.num_class
case @exponent
when :zero
  num_class.zero(@sign)
when :infinity
  num_class.infinity(@sign)
when :nan
  num_class.nan
else
  num_class.new(@sign, @significand, @exponent)
end

end



614
615
616
617
618
619
620
621
622
623
624
625
626
627
# File 'lib/float-formats/classes.rb', line 614

def self.num(x)
  s, c, e = x.split
  if x.zero?
    e = :zero
  else
    case e
    when :inf
      e = :infinity
    when :nan
      e = :nan
    end
  end
  new([s, c, e])
end

.num_classObject



569
570
571
# File 'lib/float-formats/classes.rb', line 569

def self.num_class
  Num[self.radix]
end

.numerals_conversion(options = {}) ⇒ Object



573
574
575
# File 'lib/float-formats/classes.rb', line 573

def self.numerals_conversion(options = {})
  FltFmtConversion.new(self, options)
end

.pack_fields_hash(h) ⇒ Object

Produce an encoded floating point value using hash of the internal field values. Returns a Value.



917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
# File 'lib/float-formats/classes.rb', line 917

def self.pack_fields_hash(h)
  if @splitted_fields.nil?
    pack_fields @field_meaning.collect{|f| h[f]}
  else
    flds = [nil]*@field_meaning.size
    @fields.each_key do |f|
      splits = @splitted_fields[f]
      if splits
        v = h[f]
        splits.each do |i|
          k = fields_radix**(@field_lengths[i])
          flds[i] = v % k
          v /= k
        end
      else
        flds[@field_meaning.index(f)] = h[f]
      end
    end
    pack_fields flds
  end
end

.radix_log(x) ⇒ Object

radix-base logarithm



490
491
492
# File 'lib/float-formats/classes.rb', line 490

def self.radix_log(x)
  Math.log(x)/Math.log(radix)
end

.radix_log10Object

base-10 logarithm of the radix



486
487
488
# File 'lib/float-formats/classes.rb', line 486

def self.radix_log10
  Math.log(radix)/Math.log(10)
end

.radix_max_exp(significand_mode = :scientific_significand) ⇒ Object

Maximum exponent



547
548
549
550
551
552
553
554
555
556
# File 'lib/float-formats/classes.rb', line 547

def self.radix_max_exp(significand_mode = :scientific_significand)
  case significand_mode
    when :integral_significand
      @integral_max_exp
    when :fractional_significand
      @fractional_max_exp
    when :scientific_significand
      @scientific_max_exp
  end
end

.radix_min_exp(significand_mode = :scientific_significand) ⇒ Object

Mminimum exponent



558
559
560
561
562
563
564
565
566
567
# File 'lib/float-formats/classes.rb', line 558

def self.radix_min_exp(significand_mode = :scientific_significand)
  case significand_mode
    when :integral_significand
      @integral_min_exp
    when :fractional_significand
      @fractional_min_exp
    when :scientific_significand
      @scientific_min_exp
  end
end

.radix_power(n) ⇒ Object

compute a power of the radix (base)



481
482
483
# File 'lib/float-formats/classes.rb', line 481

def self.radix_power(n)
  radix**n
end

.rounding_modeObject

Rounding mode use for this floating-point format; can be one of:

:half_even

round to nearest with ties toward an even digits

:half_up

round to nearest with ties toward infinity (away from zero)

:half_down

round to nearest with ties toward zero

nil

rounding mode not specified



535
536
537
# File 'lib/float-formats/classes.rb', line 535

def self.rounding_mode
  @round
end

.sign_from_unit(u) ⇒ Object



526
527
528
# File 'lib/float-formats/classes.rb', line 526

def self.sign_from_unit(u)
  u<0 ? minus_sign_value : 0
end

.sign_to_unit(s) ⇒ Object



522
523
524
# File 'lib/float-formats/classes.rb', line 522

def self.sign_to_unit(s)
  s==0 ? +1 : -1 # ((-1)**s)
end

.strict_epsilon(sign = +1, round = nil) ⇒ Object

The strict epsilon is the smallest value that produces something different from 1.0 wehen added to 1.0. It may be smaller than the general epsilon, because of the particular rounding rules used with the floating point format. This is only meaningful when well-defined rules are used for rounding the result of floating-point addition. Note that (in pseudo-code):

((1.0+strict_epsilon)-1.0)==epsilon

TODO: use Flt::Num



762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
# File 'lib/float-formats/classes.rb', line 762

def self.strict_epsilon(sign=+1, round=nil)
  round ||= @round
  s = sign
  m = minimum_normalized_integral_significand
  e = 2*(1-significand_digits)
  # assume radix is even
  case @round
  when :down, :floor, :any_rounding, nil
    e = 2*(1-significand_digits)
    m = minimum_normalized_integral_significand
  when :half_even, :half_down
    e = 1-2*significand_digits
    m = 1 + radix_power(significand_digits)/2
  when :half_up
    e = 1-2*significand_digits
    m = radix_power(significand_digits)/2
  when :ceiling, :up, :up05
    return min_value
  end
  return_value sign,m,e

end

.switch_sign_value(v) ⇒ Object

switch between the encodings of minus and plus



518
519
520
# File 'lib/float-formats/classes.rb', line 518

def self.switch_sign_value(v)
  (v==0) ? minus_sign_value : 0
end

.unpack_fields_hash(v) ⇒ Object

Converts en ancoded floating point number to hash containing the internal fields that define the number. Accepts either a Value or a byte String.



888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
# File 'lib/float-formats/classes.rb', line 888

def self.unpack_fields_hash(v)
  a = unpack_fields(v)
  h = {}
  if @splitted_fields.nil?
    (0...a.size).each do |i|
      h[@field_meaning[i]] = a[i]
    end
  else

    @fields.each_key do |f|
      splits = @splitted_fields[f]
      if splits
        v = 0
        k = 1
        splits.each do |i|
          v += k*a[i]
          k *= fields_radix**(@field_lengths[i])
        end
        h[f] = v
      else
        h[f] = a[@field_meaning.index(f)]
      end
    end
  end
  h
end

.zero(sign = +1) ⇒ Object

Floating point representation of zero.



800
801
802
# File 'lib/float-formats/classes.rb', line 800

def self.zero(sign=+1)
  return_value sign, 0, :zero
end

Instance Method Details

#<=>(other) ⇒ Object



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/float-formats/classes.rb', line 284

def <=>(other)
  return 1 if nan? || other.nan?
  return 0 if zero? && other.zero?
  this_sign,this_significand,this_exponent = split
  other_sign, other_significand, other_exponent = other.split
  return -1 if other_sign < this_sign
  return 1 if other_sign > this_sign
  return 0 if infinite? && other.infinite?

  if this_sign<0
    this_significand,other_significand = other_significand,this_significand
    this_exponent,other_exponent = other_exponent,this_exponent
  end

  if this_exponent==other_exponent
    return this_significand <=> other_significand
  else
    mns = form_class.minimum_normalized_integral_significand
    this_normal = this_significand >= mns
    other_normal = other_significand >= mns
    if this_normal && other_normal
      return this_exponent <=> other_exponent
    else
      min_exp = form_class.radix_min_exp(:integral_significand)
      max_exp = form_class.radix_max_exp(:integral_significand)

      while this_significand<mns && this_exponent>min_exp
        this_exponent -= 1
        this_significand *= form_class.radix
      end

      while other_significand<mns && other_exponent>min_exp
        other_exponent -= 1
        other_significand *= form_class.radix
      end

      if this_exponent==other_exponent
        return this_significand <=> other_significand
      else
        return this_exponent <=> other_exponent
      end
    end
  end
end

#convert_to(fpclass, options = {}) ⇒ Object

Converts a floating point value to another format



192
193
194
# File 'lib/float-formats/classes.rb', line 192

def convert_to(fpclass, options = {})
  Numerals::Conversions.convert(self, options.merge(type: fpclass))
end

#form_classObject



336
337
338
# File 'lib/float-formats/classes.rb', line 336

def form_class
  self.class
end

#fp_formatObject



333
334
335
# File 'lib/float-formats/classes.rb', line 333

def fp_format
  form_class
end

#infinite?Boolean

Returns:

  • (Boolean)


112
113
114
# File 'lib/float-formats/classes.rb', line 112

def infinite?
  return @exponent==:infinity
end

#minusObject

Computes the negation of a floating point value (unary minus)



187
188
189
# File 'lib/float-formats/classes.rb', line 187

def minus
  form_class.new(-@sign,@significand,@exponent)
end

#nan?Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/float-formats/classes.rb', line 104

def nan?
  @exponent == :nan
end

#next_minusObject

Computes the previous adjacent floating point value. Accepts either a Value or a byte String. Returns a Value.



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/float-formats/classes.rb', line 236

def next_minus
  s,f,e = self.class.canonicalized(@sign,@significand,@exponent,true)
  return minus.next_plus.minus if s<0
  return self.next_plus.minus if e==:zero
  if e!=:nan
    if e == :infinity
      f = form_class.maximum_integral_significand
      e = form_class.radix_max_exp(:integral_significand)
    else
      f -= 1
      if f<form_class.minimum_normalized_integral_significand
        if e!=:denormal && e>form_class.radix_min_exp(:integral_significand)
          e -= 1
          f *= form_class.radix
        else
          if form_class.gradual_underflow?
            e = :denormal
          else
            e = :zero
          end
        end
      end
    end
  end
  form_class.new s, f, e
end

#next_plusObject

Computes the next adjacent floating point value. Accepts either a Value or a byte String. Returns a Value. TODO: use Flt



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/float-formats/classes.rb', line 200

def next_plus
  s,f,e = self.class.canonicalized(@sign,@significand,@exponent,true)
  return minus.next_minus.minus if s<0 && e!=:zero
  s = -s if e==:zero && s<0

  if e!=:nan && e!=:infinity
    if f==0
      if form_class.gradual_underflow?
        e = form_class.radix_min_exp(:integral_significand)
        f = 1
      else
        e = form_class.radix_min_exp(:integral_significand)
        f = form_class.minimum_normalized_integral_significand
      end
    else
      f += 1
    end
    if f>=form_class.radix_power(form_class.significand_digits)
      f /= form_class.radix
      if e==:denormal
        e = form_class.radix_min_exp(:integral_significand)
      else
        e += 1
      end
      if e>form_class.radix_max_exp(:integral_significand)
        e = :infinity
        f = 0
      end
    end
    form_class.new s, f, e
  end
end

#normal?Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/float-formats/classes.rb', line 120

def normal?
  @exponend.kind_of?(Integer) && @significand>=self.class.minimum_normalized_integral_significand
end

#splitObject



100
101
102
# File 'lib/float-formats/classes.rb', line 100

def split
  return [@sign,@significand,@exponent]
end

#subnormal?Boolean

Returns:

  • (Boolean)


116
117
118
# File 'lib/float-formats/classes.rb', line 116

def subnormal?
  return @exponent==:denormal || (@significand.kind_of?(Integer) && @significand<self.class.minimum_normalized_integral_significand)
end

#to(number_class, mode = :approx) ⇒ Object



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/float-formats/classes.rb', line 143

def to(number_class, mode = :approx)
  if number_class == Bytes
    to_bytes
  elsif number_class == String
    mode = Numerals::Format[] if mode == :approx
    to_text(mode)
  elsif Numerals::Format === number_class
    to_text(number_class)
  elsif number_class == Array
    split
  elsif Symbol === number_class
    send "to_#{number_class}"
  elsif number_class.is_a?(Flt::Num)  && number_class.radix == form_class.radix
    self.to_num
  elsif number_class.is_a?(FormatBase)
    number_class.from_number(self, mode)
  else # assume number_class.ancestors.include?(Numeric) (number_class < Numeric)
    options = {
      type: number_class,
      exact_input: (mode != :approx),
      output_mode: :fixed
    }
    Numerals::Conversions.convert(self, options)
  end
end

#to_aObject



96
97
98
# File 'lib/float-formats/classes.rb', line 96

def to_a
  split
end

#to_bitsObject



168
169
170
# File 'lib/float-formats/classes.rb', line 168

def to_bits
  to_bytes.to_bits(form_class.endianness,false,form_class.total_bits)
end

#to_bits_text(base) ⇒ Object

Returns the encoded integral value of a floating point number as a text representation in a given base. Accepts either a Value or a byte String.



174
175
176
177
178
179
180
181
182
183
184
# File 'lib/float-formats/classes.rb', line 174

def to_bits_text(base)
  to_bits.to_s(base)
  #i = to_bits
  #fmt = Numerals::Format[base: base]
  #if [2,4,8,16].include?(base)
  #  n = (Math.log(base)/Math.log(2)).round.to_i
  #  digits = (form_class.total_bits+n-1)/n
  #  fmt.set_trailing_zeros!(digits)
  #end
  #fmt.writ(i.to_i)
end

#to_bytesObject



133
134
135
# File 'lib/float-formats/classes.rb', line 133

def to_bytes
  form_class.pack(@sign,@significand,@exponent)
end

#to_hex(sep_bytes = false) ⇒ Object



136
137
138
139
140
141
142
# File 'lib/float-formats/classes.rb', line 136

def to_hex(sep_bytes=false)
  if (form_class.total_bits % 8)==0
    to_bytes.to_hex(sep_bytes)
  else
    to_bits.to_hex
  end
end

#to_numObject



586
587
588
589
590
591
592
593
594
595
596
597
# File 'lib/float-formats/classes.rb', line 586

def to_num
  s, c, e = split
  case e
  when :zero
    e = 0
  when :infinity
    e = :inf
  when :nan
    e = :nan
  end
  form_class.num_class.Num(s, c, e)
end

#to_text(fmt = ) ⇒ Object

from/to integral_sign_significand_exponent



126
127
128
129
130
131
# File 'lib/float-formats/classes.rb', line 126

def to_text(fmt = Numerals::Format[])
  if infinite?
    fmt = fmt[symbols: [show_plus: true]]
  end
  fmt.write(self)
end

#ulpObject

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



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/float-formats/classes.rb', line 265

def ulp
  sign,sig,exp = @sign,@significand,@exponent

  mnexp = form_class.radix_min_exp(:integral_significand)
  mxexp = form_class.radix_max_exp(:integral_significand)
  prec = form_class.significand_digits

  if exp==:nan
  elsif exp==:infinity
    sign,sig,exp = 1,1,mxexp
  elsif exp==:zero || exp <= mnexp
    return form_class.min_value
  else
    exp -= 1 if sig==form_class.minimum_normalized_integral_significand
    sign,sig,exp = 1,1,exp
  end
  form_class.new sign, sig, exp
end

#zero?Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/float-formats/classes.rb', line 108

def zero?
  return @exponent==:zero || @significand==0
end