class ZXLib::Math

A module with the ZXReal struct definition and ZX-Spectrum FP helpers.

Macros can be used to convert 32-bit integers to and from floating point values.

Example:

require('zxlib/math')

class TestMath
  include Z80
  include Z80::TAP

  ZXReal = ZXLib::Math::ZXReal

  chan_open addr 0x1601

  export :auto
  start       ld a, 2
              call chan_open
              ld hl, pi
              call math.print_fp_hl
              ret

  pi          data ZXReal, Math::PI

  import :math, ZXLib::Math
end

Constants

EPSILON

ZX-Spectrum's float number epsilon

Public Class Methods

pack_number(num, simplified_int=true) click to toggle source

Converts num to a ZX-Spectrum's real number encoded as a 5-byte binary string.

simplified_int indicates if the integers in the range of -65535..65535 should be stored in a simplified integer form.

Returns binary string.

# File lib/zxlib/math.rb, line 54
def self.pack_number(num, simplified_int=true)
    sgn = num < 0
    if simplified_int && num == num.truncate && -65535 <= num && num <= 65535
        [0,
         sgn ? -1 : 0,
         num,
         0].pack('CcvC')
    else
        m = (sgn ? -num : num).to_f
        e = (::Math.log2(m)+1.0).floor
        raise "overflow error" if e > 127
        if e < -127
            [0].pack('C')*5
        else
            # m = m*(2**-e)
            if e < 0
                m = m*(1<< (-e))
            else
                m = m/(1<<e)
            end
            [
                e + 128,
                sgn ? (m*(1<<32)).truncate : (m*(1<<32)).truncate ^ (1<<31)
            ].pack('CN')
        end
    end
end
unpack_number(bin, simplified_int_as_fixnum=true) click to toggle source

Converts a ZX-Spectrum's real number as a 5-byte binary string to Numeric value.

simplified_int_as_fixnum indicates if the number encoded as a simple integer should be returned as a Fixnum.

Returns Float or Fixnum.

# File lib/zxlib/math.rb, line 87
def self.unpack_number(bin, simplified_int_as_fixnum=true)
    raise ArgumentError unless String === bin && bin.bytesize >= 5
    e, m = bin.unpack('CN')
    if e.zero?
        sgn, val, z = bin.unpack('xcvC')
        if z.zero?
            val = case sgn
            when 0 then val
            when -1 then val-0x10000
            else
                raise "simplified binary integer parse error"
            end
            val = val.to_f unless simplified_int_as_fixnum
            return val
        end
    end
    e -= 128
    sgn = if (m & (1<<31)).zero?
        m |= (1<<31)
        false
    else
        true
    end
    val = m.to_f/(1<<32)
    # m = m/(2**-e)
    val = if e < 0
        val/(1<< (-e))
    else
        val*(1<<e)
    end
    sgn ? -val : val
end

Public Instance Methods

print_fp_hl click to toggle source

Call print_fp_hl with hl pointing to the 1st byte of a ZXReal number to print that number to the currently opened channel.

After return the ZF flag can be inspected to check if the number was 0.