Class: Flt::FormatBase
- Inherits:
-
Object
- Object
- Flt::FormatBase
- 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
Direct Known Subclasses
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
-
.hidden_bit ⇒ Object
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. -
.parameters ⇒ Object
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. -
.radix ⇒ Object
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. -
.significand_digits ⇒ Object
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.
Instance Attribute Summary collapse
-
#exponent ⇒ Object
readonly
Returns the value of attribute exponent.
-
#sign ⇒ Object
readonly
Returns the value of attribute sign.
-
#significand ⇒ Object
readonly
Returns the value of attribute significand.
Class Method Summary collapse
-
.arithmetic ⇒ Object
Set up the arithmetic environment; the arithmetic type is passed to the block.
-
.arithmetic_type ⇒ Object
Type used internally for arithmetic operations.
-
.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.
- .canonicalized(s, m, e, normalize = nil) ⇒ Object
- .context ⇒ Object
-
.decimal_digits_necessary ⇒ Object
number of decimal digits necessary to unambiguosly define any floating point value.
-
.decimal_digits_stored ⇒ Object
number of decimal digits that can be stored in a floating point value and restored unaltered.
-
.decimal_max_exp ⇒ Object
Maximum integer such that 10 raised to that power is in the range of the normalised floating point numbers.
-
.decimal_min_exp ⇒ Object
Minimum negative integer such that 10 raised to that power is in the range of the normalised floating point numbers.
-
.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). -
.endianness ⇒ Object
Endianness of the format (:little_endian, :big_endian or :little_big_endian).
-
.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).
-
.from(*args) ⇒ Object
from methods.
-
.from_bits(i) ⇒ Object
Defines a floating-point number from the encoded integral value.
-
.from_bits_text(txt, base) ⇒ Object
Defines a floating-point number from a text representation of the encoded integral value in a given base.
- .from_bytes(b) ⇒ Object
- .from_hex(hex) ⇒ Object
- .from_number(v, mode = :approx) ⇒ Object
- .from_text(txt, *args) ⇒ Object
-
.gradual_underflow? ⇒ Boolean
Does the format support gradual underflow? (denormalized numbers).
-
.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.
-
.infinity(sign = +1) ⇒ Object
Floating point representation of infinity.
- .join(sign, significand, exponent) ⇒ Object
-
.max_value(sign = +1) ⇒ Object
Greatest finite normalized floating point number in the representation.
- .maximum_integral_significand ⇒ Object
-
.min_normalized_value(sign = +1) ⇒ Object
Smallest normalized floating point number greater than zero in the representation.
-
.min_value(sign = +1) ⇒ Object
Smallest floating point number greater than zero in the representation, including denormalized values if the representation supports it.
- .minimum_normalized_integral_significand ⇒ Object
-
.minus_sign_value ⇒ Object
Stored (integral) value for the minus sign.
-
.nan ⇒ Object
Floating point representation of Not-a-Number.
-
.num(x) ⇒ Object
def to_num # num_class = Flt::Num 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.
- .num_class ⇒ Object
- .numerals_conversion(options = {}) ⇒ Object
-
.pack_fields_hash(h) ⇒ Object
Produce an encoded floating point value using hash of the internal field values.
-
.radix_log(x) ⇒ Object
radix-base logarithm.
-
.radix_log10 ⇒ Object
base-10 logarithm of the radix.
-
.radix_max_exp(significand_mode = :scientific_significand) ⇒ Object
Maximum exponent.
-
.radix_min_exp(significand_mode = :scientific_significand) ⇒ Object
Mminimum exponent.
-
.radix_power(n) ⇒ Object
compute a power of the radix (base).
-
.rounding_mode ⇒ Object
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. - .sign_from_unit(u) ⇒ Object
- .sign_to_unit(s) ⇒ Object
-
.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.
-
.switch_sign_value(v) ⇒ Object
switch between the encodings of minus and plus.
-
.unpack_fields_hash(v) ⇒ Object
Converts en ancoded floating point number to hash containing the internal fields that define the number.
-
.zero(sign = +1) ⇒ Object
Floating point representation of zero.
Instance Method Summary collapse
- #<=>(other) ⇒ Object
-
#convert_to(fpclass, options = {}) ⇒ Object
Converts a floating point value to another format.
- #form_class ⇒ Object
- #fp_format ⇒ Object
- #infinite? ⇒ Boolean
-
#initialize(*args) ⇒ FormatBase
constructor
A new instance of FormatBase.
-
#minus ⇒ Object
Computes the negation of a floating point value (unary minus).
- #nan? ⇒ Boolean
-
#next_minus ⇒ Object
Computes the previous adjacent floating point value.
-
#next_plus ⇒ Object
Computes the next adjacent floating point value.
- #normal? ⇒ Boolean
- #split ⇒ Object
- #subnormal? ⇒ Boolean
- #to(number_class, mode = :approx) ⇒ Object
- #to_a ⇒ Object
- #to_bits ⇒ Object
-
#to_bits_text(base) ⇒ Object
Returns the encoded integral value of a floating point number as a text representation in a given base.
- #to_bytes ⇒ Object
- #to_hex(sep_bytes = false) ⇒ Object
- #to_num ⇒ Object
-
#to_text(fmt = ) ⇒ Object
from/to integral_sign_significand_exponent.
-
#ulp ⇒ Object
ulp (unit in the last place) according to the definition proposed by J.M.
- #zero? ⇒ Boolean
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_bit ⇒ Object (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 |
.parameters ⇒ Object (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 |
.radix ⇒ Object (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_digits ⇒ Object (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
#exponent ⇒ Object (readonly)
Returns the value of attribute exponent.
94 95 96 |
# File 'lib/float-formats/classes.rb', line 94 def exponent @exponent end |
#sign ⇒ Object (readonly)
Returns the value of attribute sign.
94 95 96 |
# File 'lib/float-formats/classes.rb', line 94 def sign @sign end |
#significand ⇒ Object (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
.arithmetic ⇒ Object
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_type ⇒ Object
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 |
.context ⇒ Object
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_necessary ⇒ Object
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_stored ⇒ Object
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_exp ⇒ Object
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_exp ⇒ Object
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).
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 |
.endianness ⇒ Object
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 = { type: self, exact_input: (mode != :approx), output_mode: @normalized ? :fixed : :short } Numerals::Conversions.convert(v, ) 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)
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_significand ⇒ Object
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_significand ⇒ Object
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_value ⇒ Object
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 |
.nan ⇒ Object
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_class ⇒ Object
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( = {}) FltFmtConversion.new(self, ) 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_log10 ⇒ Object
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_mode ⇒ Object
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, = {}) Numerals::Conversions.convert(self, .merge(type: fpclass)) end |
#form_class ⇒ Object
336 337 338 |
# File 'lib/float-formats/classes.rb', line 336 def form_class self.class end |
#fp_format ⇒ Object
333 334 335 |
# File 'lib/float-formats/classes.rb', line 333 def fp_format form_class end |
#infinite? ⇒ Boolean
112 113 114 |
# File 'lib/float-formats/classes.rb', line 112 def infinite? return @exponent==:infinity end |
#minus ⇒ Object
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
104 105 106 |
# File 'lib/float-formats/classes.rb', line 104 def nan? @exponent == :nan end |
#next_minus ⇒ Object
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_plus ⇒ Object
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
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 |
#split ⇒ Object
100 101 102 |
# File 'lib/float-formats/classes.rb', line 100 def split return [@sign,@significand,@exponent] end |
#subnormal? ⇒ 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) = { type: number_class, exact_input: (mode != :approx), output_mode: :fixed } Numerals::Conversions.convert(self, ) end end |
#to_a ⇒ Object
96 97 98 |
# File 'lib/float-formats/classes.rb', line 96 def to_a split end |
#to_bits ⇒ Object
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_bytes ⇒ Object
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_num ⇒ Object
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 |
#ulp ⇒ 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
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
108 109 110 |
# File 'lib/float-formats/classes.rb', line 108 def zero? return @exponent==:zero || @significand==0 end |