Module: Flt

Included in:
FormatBase, FormatBase
Defined in:
lib/float-formats.rb,
lib/float-formats/bytes.rb,
lib/float-formats/native.rb,
lib/float-formats/classes.rb,
lib/float-formats/formats.rb,
lib/float-formats/version.rb

Overview

Flt contains constants for common floating point formats.

Defined Under Namespace

Modules: Frmts, IEEE Classes: BCDFormat, BinaryFormat, Bits, Bytes, C51BCDFormat, CDCFormat, DPDFormat, DecimalFormatBase, DoubleFormat, FieldsInBitsFormatBase, FormatBase, HexadecimalFormat

Constant Summary collapse

IEEE_binaryx =

old names

IEEE_binary80
IEEE_HALF =
IEEE_binary16
IEEE_SINGLE =
IEEE_binary32
IEEE_DOUBLE =
IEEE_binary64
IEEE_EXTENDED =
IEEE_binary80
IEEE_QUAD =
IEEE_binary128
IEEE_128 =
IEEE_binary128
IEEE_H_BE =
IEEE_binary16_BE
IEEE_S_BE =
IEEE_binary32_BE
IEEE_D_BE =
IEEE_binary64_BE
IEEE_X_BE =
IEEE_binary80_BE
IEEE_128_BE =
IEEE_binary128_BE
IEEE_Q_BE =
IEEE_binary128_BE
IEEE_DEC32 =

old names

IEEE_decimal32
IEEE_DEC64 =
IEEE_decimal64
IEEE_DEC128 =
IEEE_decimal128
RPL =
SATURN
RPL_X =
SATURN_X
APPLE =

Sofware floating point implementatin for the Apple II (6502) the significand & sign are a single field in two’s commplement

APPLE_INSANE

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.bcd2dpd(arg) ⇒ Object

Compress BCD to Densely Packed Decimal

adapted from Mike Cowlishaw’s Rexx program:

http://www2.hursley.ibm.com/decimal/DPDecimal.html


338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# File 'lib/float-formats/bytes.rb', line 338

def bcd2dpd(arg)
  # assign each bit to a variable, named as in the description
  a,b,c,d,e,f,g,h,i,j,k,m = ("%012B"%arg).split('').collect{|bit| bit.to_i}

  # derive the result bits, using boolean expressions only
  #-- [the operators are: '&'=AND, '|'=OR, '\'=NOT.]
  p=b | (a & j) | (a & f & i)
  q=c | (a & k) | (a & g & i)
  r=d
  s=(f & (bitnot(a) | bitnot(i))) | (bitnot(a) & e & j) | (e & i)
  t=g  | (bitnot(a) & e &k) | (a & i)
  u=h
  v=a | e | i
  w=a | (e & i) | (bitnot(e) & j)
  x=e | (a & i) | (bitnot(a) & k)
  y=m

  # concatenate the bits and return
    # result = [p,q,r,s,t,u,v,w,x,y].collect{|bit| bit.to_s}.inject{|aa,bb|aa+bb}.to_i(2)
    result = 0
    [p,q,r,s,t,u,v,w,x,y].each do |bit|
      result <<= 1
      result |= bit
    end
  result
end

.bitnot(b) ⇒ Object

Negate a bit. Auxiliar method for DPD conversions



330
331
332
# File 'lib/float-formats/bytes.rb', line 330

def bitnot(b)
  (~b)&1
end

.convert_bytes(bytes, from_format, to_format) ⇒ Object



1986
1987
1988
# File 'lib/float-formats/classes.rb', line 1986

def convert_bytes(bytes,from_format,to_format)
  from_format.from_bytes(bytes).convert_to(to_format)
end

.dbl_from_float(val, little_endian = true) ⇒ Object

generate a DBL value stored in a byte string given a Float value



89
90
91
92
# File 'lib/float-formats/native.rb', line 89

def dbl_from_float(val, little_endian=true)
  code = little_endian ? 'E':'G'
  [val].pack(code)
end

.dbl_from_text(txt, little_endian = true) ⇒ Object

generate a DBL value stored in a byte string given a decimal value formatted as text



83
84
85
86
# File 'lib/float-formats/native.rb', line 83

def dbl_from_text(txt, little_endian=true)
  code = little_endian ? 'E':'G'
  [txt].pack(code)
end

.dbl_to_float(sgl, little_endian = true) ⇒ Object

convert a DBL value stored in a byte string to a Float value



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

def dbl_to_float(sgl, little_endian=true)
  code = little_endian ? 'E':'G'
  sgl.unpack(code)[0]
end

.define(*arguments) {|cls| ... } ⇒ Object

Yields:

  • (cls)


1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
# File 'lib/float-formats/classes.rb', line 1966

def define(*arguments)
  raise "Invalid number of arguments for Flt definitions." if arguments.size<2 || arguments.size>3
  if arguments.first.kind_of?(Class)
    base,name,parameters = arguments
  elsif arguments[1].kind_of?(Class)
    name,base,parameters = arguments
  else
    name,parameters = arguments
    base = parameters[:base] || FormatBase
  end
  Flt.const_set name, cls=Class.new(base)
  cls.define parameters
  constructor = lambda { |*args| cls.new(*args) }
  Flt.send :define_method,name,constructor
  Flt.send :module_function, name
  yield cls if block_given?
end

.dpd2bcd(arg) ⇒ Object

Expand Densely Packed Decimal to BCD

adapted from Mike Cowlishaw’s Rexx program:

http://www2.hursley.ibm.com/decimal/DPDecimal.html


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
# File 'lib/float-formats/bytes.rb', line 369

def dpd2bcd(arg)

  # assign each bit to a variable, named as in the description
  p,q,r,s,t,u,v,w,x,y = ("%010B"%arg).split('').collect{|bit| bit.to_i}

  # derive the result bits, using boolean expressions only
  a= (v & w) & (bitnot(s) | t | bitnot(x))
  b=p & (bitnot(v) | bitnot(w) | (s & bitnot(t) & x))
  c=q & (bitnot(v) | bitnot(w) | (s & bitnot(t) & x))
  d=r
  e=v & ((bitnot(w) & x) | (bitnot(t) & x) | (s & x))
  f=(s & (bitnot(v) | bitnot(x))) | (p & bitnot(s) & t & v & w & x)
  g=(t & (bitnot(v) | bitnot(x))) | (q & bitnot(s) & t & w)
  h=u
  i=v & ((bitnot(w) & bitnot(x)) | (w & x & (s | t)))
  j=(bitnot(v) & w) | (s & v & bitnot(w) & x) | (p & w & (bitnot(x) | (bitnot(s) & bitnot(t))))
  k=(bitnot(v) & x) | (t & bitnot(w) & x) | (q & v & w & (bitnot(x) | (bitnot(s) & bitnot(t))))
  m=y
  # concatenate the bits and return
  # result = [a,b,c,d,e,f,g,h,i,j,k,m].collect{|bit| bit.to_s}.inject{|aa,bb|aa+bb}.to_i(2)
    result = 0
    [a,b,c,d,e,f,g,h,i,j,k,m].each do |bit|
      result <<= 1
      result |= bit
    end
  result
end

.dpd_to_hexbcd(dpd, dpd_bits, endianness = :big_endian) ⇒ Object

Unpack DPD digits



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
# File 'lib/float-formats/bytes.rb', line 430

def dpd_to_hexbcd(dpd, dpd_bits, endianness=:big_endian)

  bcd = ""

  while dpd_bits>=10
    v = dpd2bcd(dpd & 0x3FF)
    dpd >>= 10
    dpd_bits -= 10
    bcd = ("%03X"%v)+bcd
  end

  if dpd_bits>0
    case dpd_bits
      when 4
        v = dpd & 0xF
        n = 1
      when 7
        v = dpd & 0x7F
        n = 2
      else
        raise "Invalid DPD data"
    end
    v = dpd2bcd(v,true)
    bcd = ("%0#{n}X"%v)+bcd
  end

  bcd = bcd.reverse if endianness==:little_endian

  bcd

end

.float_bin(x) ⇒ Object

binary representation



27
28
29
# File 'lib/float-formats/native.rb', line 27

def float_bin(x)
  Numerals::Format[:free, :exact_input, :scientific, base: 2].write(x)
end

.float_dec(x) ⇒ Object

complete exact decimal representation



22
23
24
# File 'lib/float-formats/native.rb', line 22

def float_dec(x)
  Numerals::Format[:free, :exact_input].write(x)
end

.float_from_integral_sign_significand_exponent(sgn, s, e) ⇒ Object



45
46
47
# File 'lib/float-formats/native.rb', line 45

def float_from_integral_sign_significand_exponent(sgn,s,e)
  Float.context.Num(sgn,s,e)
end

.float_from_integral_significand_exponent(s, e) ⇒ Object

compose float from significand and exponent



37
38
39
# File 'lib/float-formats/native.rb', line 37

def float_from_integral_significand_exponent(s,e)
  Float.context.Num(s,e)
end

.float_shortest_dec(x) ⇒ Object

shortest decimal unambiguous reprentation



12
13
14
# File 'lib/float-formats/native.rb', line 12

def float_shortest_dec(x)
  Numerals::Format[:short].write(x)
end

.float_significant_dec(x) ⇒ Object

decimal representation showing all significant digits



17
18
19
# File 'lib/float-formats/native.rb', line 17

def float_significant_dec(x)
  Numerals::Format[:free].write(x)
end

.float_to_integral_sign_significand_exponent(x) ⇒ Object



41
42
43
# File 'lib/float-formats/native.rb', line 41

def float_to_integral_sign_significand_exponent(x)
  Float.context.split(x)
end

.float_to_integral_significand_exponent(x) ⇒ Object

decompose a float into a signed integer significand and exponent (base Float::RADIX)



32
33
34
# File 'lib/float-formats/native.rb', line 32

def float_to_integral_significand_exponent(x)
  Float.context.to_int_scale(x)
end

.hex_from_float(v) ⇒ Object

convert a float to C99’s hexadecimal notation



50
51
52
# File 'lib/float-formats/native.rb', line 50

def hex_from_float(v)
  Numerals::Format[:hexbin].write(v)
end

.hex_to_float(txt) ⇒ Object

convert a string formatted in C99’s hexadecimal notation to a float



55
56
57
58
59
# File 'lib/float-formats/native.rb', line 55

def hex_to_float(txt)
  # Numerals::Format[:hexbin].read(txt, type: Float)
  # txt.scanf("%A").first
  Float(txt)
end

.hexbcd_to_dpd(bcd, endianness = :big_endian) ⇒ Object

Pack a bcd digits string into DPD



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
# File 'lib/float-formats/bytes.rb', line 398

def hexbcd_to_dpd(bcd, endianness=:big_endian)

  n = bcd.size
  dpd = 0
  dpd_bits = 0

  i = 0
  m = n%3
  if m>0
    v = bcd2dpd(bcd[0,m].to_i(16))
    i += m
    n -= m
    bits = m==1 ? 4 : 7
    dpd_bits += bits
    dpd <<= bits
    dpd |= v
  end

  while n>0
    v = bcd2dpd(bcd[i,3].to_i(16))
    i += 3
    n -= 3
    bits = 10
    dpd_bits += bits
    dpd <<= bits
    dpd |= v
  end

  [dpd, dpd_bits]
end

.sgl_from_float(val, little_endian = true) ⇒ Object

generate a SGL value stored in a byte string given a Float value



70
71
72
73
# File 'lib/float-formats/native.rb', line 70

def sgl_from_float(val, little_endian=true)
  code = little_endian ? 'e':'g'
  [val].pack(code)
end

.sgl_from_text(txt, little_endian = true) ⇒ Object

generate a SGL value stored in a byte string given a decimal value formatted as text



64
65
66
67
# File 'lib/float-formats/native.rb', line 64

def sgl_from_text(txt, little_endian=true)
  code = little_endian ? 'e':'g'
  [txt].pack(code)
end

.sgl_to_float(sgl, littel_endian = true) ⇒ Object

convert a SGL value stored in a byte string to a Float value



76
77
78
79
# File 'lib/float-formats/native.rb', line 76

def sgl_to_float(sgl, littel_endian=true)
  code = little_endian ? 'e':'g'
  sgl.unpack(code)[0]
end

Instance Method Details

#*(v) ⇒ Object



1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
# File 'lib/float-formats/classes.rb', line 1746

def *(v)
  # TODO: coercion
  if v.form_class==form_class
    form_class.arithmetic do |t|
      x = to(t,:exact) * v.to(t,:exact)
      form_class.from_number(x,:exact)
    end
  else
    # TODO
  end
end

#+(v) ⇒ Object



1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
# File 'lib/float-formats/classes.rb', line 1713

def +(v)
  # TODO: coercion
  if v.form_class==form_class
    form_class.arithmetic do |t|
      x = to(t,:exact) + v.to(t,:exact)
      form_class.from_number(x,:exact)
    end
  else
    # TODO
  end
end

#-(v) ⇒ Object



1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
# File 'lib/float-formats/classes.rb', line 1735

def -(v)
  # TODO: coercion
  if v.form_class==form_class
    form_class.arithmetic do |t|
      x = to(t,:exact) - v.to(t,:exact)
      form_class.from_number(x,:exact)
    end
  else
    # TODO
  end
end

#-@Object



1710
1711
1712
# File 'lib/float-formats/classes.rb', line 1710

def -@
  minus
end

#/(v) ⇒ Object



1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
# File 'lib/float-formats/classes.rb', line 1724

def /(v)
  # TODO: coercion
  if v.form_class==form_class
    form_class.arithmetic do |t|
      x = to(t,:exact) / v.to(t,:exact)
      form_class.from_number(x,:exact)
    end
  else
    # TODO
  end
end