class Flt::FormatBase

General Floating Point Format Base class

Attributes

hidden_bit[R]

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

parameters[R]

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

radix[R]

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

significand_digits[R]

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

exponent[R]
sign[R]
significand[R]

Public Class Methods

bias(significand_mode = :scientific_significand) click to toggle source

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

# File lib/float-formats/classes.rb, line 647
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) click to toggle source
# File lib/float-formats/classes.rb, line 658
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
context() click to toggle source
# File lib/float-formats/classes.rb, line 581
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,
    normalized: @normalized
  )
end
decimal_digits_necessary() click to toggle source

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

# File lib/float-formats/classes.rb, line 502
def self.decimal_digits_necessary
  (significand_digits*radix_log10).ceil+1
end
decimal_digits_stored() click to toggle source

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

# File lib/float-formats/classes.rb, line 498
def self.decimal_digits_stored
  ((significand_digits-1)*radix_log10).floor
end
decimal_max_exp() click to toggle source

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

# File lib/float-formats/classes.rb, line 508
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_exp() click to toggle source

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

# File lib/float-formats/classes.rb, line 514
def self.decimal_min_exp
  (radix_min_exp(:fractional_significand)*radix_log10).ceil
end
define(params={}) { |self| ... } click to toggle source

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).

# 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
endianness() click to toggle source

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

# File lib/float-formats/classes.rb, line 635
def self.endianness
  @endianness
end
epsilon(sign=+1) click to toggle source

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

# File lib/float-formats/classes.rb, line 751
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) click to toggle source

from methods

# File lib/float-formats/classes.rb, line 827
def self.from(*args)
  new(*args)
end
from_bits(i) click to toggle source

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

# File lib/float-formats/classes.rb, line 867
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) click to toggle source

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

# File lib/float-formats/classes.rb, line 885
def self.from_bits_text(txt, base)
  i = Numerals::Format[].read(txt, type: Integer, base: base)
  from_bits i
end
from_bytes(b) click to toggle source
# File lib/float-formats/classes.rb, line 831
def self.from_bytes(b)
  return_value(*unpack(b))
end
from_hex(hex) click to toggle source
# File lib/float-formats/classes.rb, line 835
def self.from_hex(hex)
  from_bytes Bytes.from_hex(hex)
end
from_number(v, mode = :approx) click to toggle source
# File lib/float-formats/classes.rb, line 839
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) click to toggle source
# File lib/float-formats/classes.rb, line 852
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?() click to toggle source

Does the format support gradual underflow? (denormalized numbers)

# File lib/float-formats/classes.rb, line 640
def self.gradual_underflow?
  @gradual_underflow
end
half_epsilon(sign=+1) click to toggle source

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

# File lib/float-formats/classes.rb, line 794
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) click to toggle source

Floating point representation of infinity.

# File lib/float-formats/classes.rb, line 809
def self.infinity(sign=+1)
  if @infinite_encoded_exp
    return_value sign, 0, :infinity
  else
    nil
  end
end
join(sign,significand,exponent) click to toggle source
# File lib/float-formats/classes.rb, line 862
def self.join(sign,significand,exponent)
  self.new sign,significand,exponent
end
max_value(sign=+1) click to toggle source

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).

# File lib/float-formats/classes.rb, line 721
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_significand() click to toggle source
# File lib/float-formats/classes.rb, line 546
def self.maximum_integral_significand
  radix_power(significand_digits)-1
end
min_normalized_value(sign=+1) click to toggle source

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

# File lib/float-formats/classes.rb, line 729
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) click to toggle source

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.

# File lib/float-formats/classes.rb, line 739
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_significand() click to toggle source
# File lib/float-formats/classes.rb, line 543
def self.minimum_normalized_integral_significand
  radix_power(significand_digits-1)
end
minus_sign_value() click to toggle source

Stored (integral) value for the minus sign

# File lib/float-formats/classes.rb, line 518
def self.minus_sign_value
  (-1) % radix
end
nan() click to toggle source

Floating point representation of Not-a-Number.

# File lib/float-formats/classes.rb, line 817
def self.nan
  if @nan_encoded_exp
    return_value(+1, 0, :nan)
  else
    nil
  end
end
new(*args) click to toggle source
# 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
normalized?() click to toggle source
# File lib/float-formats/classes.rb, line 480
def self.normalized?
  @normalized
end
num(x) click to toggle source

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

# File lib/float-formats/classes.rb, line 619
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_class() click to toggle source
# File lib/float-formats/classes.rb, line 573
def self.num_class
  Num[self.radix]
end
numerals_conversion(options = {}) click to toggle source
# File lib/float-formats/classes.rb, line 577
def self.numerals_conversion(options = {})
  FltFmtConversion.new(self, options)
end
pack_fields_hash(h) click to toggle source

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

# File lib/float-formats/classes.rb, line 922
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) click to toggle source

radix-base logarithm

# File lib/float-formats/classes.rb, line 494
def self.radix_log(x)
  Math.log(x)/Math.log(radix)
end
radix_log10() click to toggle source

base-10 logarithm of the radix

# File lib/float-formats/classes.rb, line 490
def self.radix_log10
  Math.log(radix)/Math.log(10)
end
radix_max_exp(significand_mode = :scientific_significand) click to toggle source

Maximum exponent

# File lib/float-formats/classes.rb, line 551
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) click to toggle source

Mminimum exponent

# File lib/float-formats/classes.rb, line 562
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) click to toggle source

compute a power of the radix (base)

# File lib/float-formats/classes.rb, line 485
def self.radix_power(n)
  radix**n
end
rounding_mode() click to toggle source

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

# File lib/float-formats/classes.rb, line 539
def self.rounding_mode
  @round
end
sign_from_unit(u) click to toggle source
# File lib/float-formats/classes.rb, line 530
def self.sign_from_unit(u)
  u<0 ? minus_sign_value : 0
end
sign_to_unit(s) click to toggle source
# File lib/float-formats/classes.rb, line 526
def self.sign_to_unit(s)
  s==0 ? +1 : -1 # ((-1)**s)
end
strict_epsilon(sign=+1, round=nil) click to toggle source

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

# File lib/float-formats/classes.rb, line 767
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) click to toggle source

switch between the encodings of minus and plus

# File lib/float-formats/classes.rb, line 522
def self.switch_sign_value(v)
  (v==0) ? minus_sign_value : 0
end
unpack_fields_hash(v) click to toggle source

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

# File lib/float-formats/classes.rb, line 893
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) click to toggle source

Floating point representation of zero.

# File lib/float-formats/classes.rb, line 805
def self.zero(sign=+1)
  return_value sign, 0, :zero
end

Protected Class Methods

input_bytes(v) click to toggle source
# File lib/float-formats/classes.rb, line 705
def self.input_bytes(v)
  if v.kind_of?(FormatBase)
    raise "Invalid f.p. format" if v.fp_format!=self
    v = v.to_bytes
  elsif !v.kind_of?(Bytes)
    v = Bytes.new(v)
  end
  v
end
normalized(s,m,e) click to toggle source
# File lib/float-formats/classes.rb, line 683
def self.normalized(s,m,e)
  if m.kind_of?(Integer) && e.kind_of?(Integer)
    min_exp = radix_min_exp(:integral_significand)
    if m>0
      while m<minimum_normalized_integral_significand && e>min_exp
        e -= 1
        m *= radix
      end
      if @normalized && !@gradual_underflow
        if e<=min_exp && m<minimum_normalized_integral_significand
          m = 0
          e = :zero
        end
      end
    end
  end
  [s,m,e]
end
return_value(s,m,e,normalize=nil) click to toggle source
# File lib/float-formats/classes.rb, line 702
def self.return_value(s,m,e,normalize=nil)
  self.new s,m,e,normalize
end

Public Instance Methods

<=>(other) click to toggle source
# 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 = {}) click to toggle source

Converts a floating point value to another format

# File lib/float-formats/classes.rb, line 192
def convert_to(fpclass, options = {})
  Numerals::Conversions.convert(self, options.merge(type: fpclass))
end
form_class() click to toggle source
# File lib/float-formats/classes.rb, line 336
def form_class
  self.class
end
fp_format() click to toggle source

todo hash cononicalizing first

# File lib/float-formats/classes.rb, line 333
def fp_format
  form_class
end
infinite?() click to toggle source
# File lib/float-formats/classes.rb, line 112
def infinite?
  return @exponent==:infinity
end
minus() click to toggle source

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

# File lib/float-formats/classes.rb, line 187
def minus
  form_class.new(-@sign,@significand,@exponent)
end
nan?() click to toggle source
# File lib/float-formats/classes.rb, line 104
def nan?
  @exponent == :nan
end
next_minus() click to toggle source

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

# 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_plus() click to toggle source

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

# 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?() click to toggle source
# File lib/float-formats/classes.rb, line 120
def normal?
  @exponend.kind_of?(Integer) && @significand>=self.class.minimum_normalized_integral_significand
end
split() click to toggle source
# File lib/float-formats/classes.rb, line 100
def split
  return [@sign,@significand,@exponent]
end
subnormal?() click to toggle source
# 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) click to toggle source
# 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_a() click to toggle source
# File lib/float-formats/classes.rb, line 96
def to_a
  split
end
to_bits() click to toggle source
# 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) click to toggle source

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.

# 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_bytes() click to toggle source
# File lib/float-formats/classes.rb, line 133
def to_bytes
  form_class.pack(@sign,@significand,@exponent)
end
to_hex(sep_bytes=false) click to toggle source
# 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_num() click to toggle source
# File lib/float-formats/classes.rb, line 591
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 = Numerals::Format[]) click to toggle source

from/to integral_sign_significand_exponent

# 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
ulp() 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

# 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?() click to toggle source
# File lib/float-formats/classes.rb, line 108
def zero?
  return @exponent==:zero || @significand==0
end