module IEEE_FPU

FPU parameters can be assigneed passign a hash to the scope method:

IEEE_FPU.scope(:precision=>:single) {
  puts eval(expr)
}

An array can be passed for one (only one) of the parameters; the block will be repeated with every value of the parameter and the results will be collected in an array. For example this checks the result of an expression in all the rounding modes:

puts IEEE_FPU.scope(:rounding=>[:even,:up,:down,:zero]) {
  1.0 + Float::EPSILON/2
}.inspect

Different parameters can be passed to each call of the block by assigning an array to :parameters For example, interval arithmetic could be implementes like this:

def sum_intervals(i1,i2)
  IEEE_FPU.scope(:rounding=>[:down,:up],:parameters=>[0,1]) do |fpu,i|
    i1[i]+i2[i]
  end
end
i = sum_intervals([1.0]*2, [Float::EPSILON/2]*2)

use ieee_fpu extension

Constants

Controlfp
DN_FLUSH
DN_SAVE
EM_DENORMAL
EM_INEXACT
EM_INVALID
EM_OVERFLOW
EM_UNDERFLOW
EM_ZERODIVIDE
FE_DBLPREC
FE_DOWNWARD
FE_FLTPREC
FE_LDBLPREC
FE_TONEAREST
FE_TOWARDZERO
FE_UPWARD
FPU_DOUBLE
FPU_EXTENDED
FPU_RC_DOWN
FPU_RC_NEAREST
FPU_RC_UP
FPU_RC_ZERO
FPU_SINGLE
IC_AFFINE
IC_PROJECTIVE
MCW_DN
MCW_EM
MCW_IC
MCW_PC
MCW_RC
PC_24
PC_53
PC_64
RC_CHOP
RC_DOWN
RC_NEAR
RC_UP

Public Class Methods

fegetprec() click to toggle source
static VALUE mIEEE_FPU_fegetprec(VALUE self)
{
  return UINT2NUM(fegetprec());
}
fegetround() click to toggle source
static VALUE mIEEE_FPU_fegetround(VALUE self)
{
  return UINT2NUM(fegetround());
}
fesetprec(p1) click to toggle source
static VALUE mIEEE_FPU_fesetprec(VALUE self, VALUE prec)
{
  fesetprec(NUM2UINT(prec));
  return UINT2NUM(fegetprec());
}
fesetround(p1) click to toggle source

Set the FPU's rounding mode.

static VALUE mIEEE_FPU_fesetround(VALUE self, VALUE mode)
{
  fesetround(NUM2UINT(mode));
  return UINT2NUM(fegetround());
}
fpu_getprec() click to toggle source
static VALUE mIEEE_FPU_fpu_getprec(VALUE self)
{
  fpu_control_t mask = (_FPU_EXTENDED|_FPU_DOUBLE|_FPU_SINGLE);
  fpu_control_t c;
  _FPU_GETCW(c);  
  return UINT2NUM(c & mask);
}
fpu_getround() click to toggle source
static VALUE mIEEE_FPU_fpu_getround(VALUE self)
{
  fpu_control_t mask = (_FPU_RC_NEAREST|_FPU_RC_DOWN|_FPU_RC_UP|_FPU_RC_ZERO);
  fpu_control_t c;
  _FPU_GETCW(c);  
  return UINT2NUM(c & mask);
}
fpu_setprec(p1) click to toggle source
static VALUE mIEEE_FPU_fpu_setprec(VALUE self, VALUE prec)
{
  fpu_control_t mask = (_FPU_EXTENDED|_FPU_DOUBLE|_FPU_SINGLE);
  fpu_control_t c, new_c;
  _FPU_GETCW(c);  
  new_c = c;
  new_c &= ~mask;
  new_c |= NUM2UINT(prec);
  _FPU_SETCW(new_c);  
  return UINT2NUM(c & mask);
}
fpu_setround(p1) click to toggle source
static VALUE mIEEE_FPU_fpu_setround(VALUE self, VALUE mode)
{
  fpu_control_t mask = (_FPU_RC_NEAREST|_FPU_RC_DOWN|_FPU_RC_UP|_FPU_RC_ZERO);
  fpu_control_t c, new_c;
  _FPU_GETCW(c);  
  new_c = c;
  new_c &= ~mask;
  new_c |= NUM2UINT(mode);
  _FPU_SETCW(new_c);  
  return UINT2NUM(c & mask);
}
get_status() click to toggle source
# File lib/ieee-fpu.rb, line 85
def self.get_status
  Controlfp.call(0,0)
end
precision() click to toggle source
# File lib/ieee-fpu.rb, line 124
def self.precision
  v = get_status & MCW_PC
  p = nil
  case v
    when PC_24
      p = :single
    when PC_53
      p = :double
    when PC_64
      p = :extended
  end
  p
end
precision=(p) click to toggle source
# File lib/ieee-fpu.rb, line 137
def self.precision=(p)
  v = nil
  case p
    when :single, 24
      v = PC_24
    when :double, 53
      v = PC_53
    when :extended, 64, 112
      v = PC_64
    else
      raise Error, "Invalid precision #{p.inspect}"
  end
  Controlfp.call(v,MCW_PC) unless v.nil?
  p
end
rounding() click to toggle source
# File lib/ieee-fpu.rb, line 153
def self.rounding
  v = get_status & MCW_RC
  r = nil
  case v
    when RC_UP
      r = :up
    when RC_DOWN
      r = :down
    when RC_CHOP
      r = :zero
    when RC_NEAR
      r = :even
  end
  r
end
rounding=(r) click to toggle source
# File lib/ieee-fpu.rb, line 169
def self.rounding=(r)
  v = nil
  case r
    when :up, :plus_infinity, :positive_infinity
      v = RC_UP
    when :down, :minus_inifinity, :negative_infinity
      v = RC_DOWN
    when :zero, :truncate, :chop
      v = RC_CHOP
    when :even, :near, :unbiased
      v = RC_NEAR
    else
      raise Error, "Invalid rounding mode #{r}"
    end
  Controlfp.call(v,MCW_RC) unless v.nil?
  r
end
scope(assignments={}) { |self, param| ... } click to toggle source
# File lib/ieee-fpu.rb, line 91
def self.scope(assignments={})
  v = nil
  s = get_status
  prc = assignments[:precision]
  rnd = assignments[:rounding]
  self.precision = prc if prc && !(Array===prc)
  self.rounding =rnd if rnd && !(Array===rnd)
  if Array===prc
    param = assignments[:parameters] || [nil]*prc.size
    v = []
    i = 0
    prc.each do |p|
      self.precision = p
      v << yield(self, param[i])
      i += 1
    end
  elsif Array===rnd
    param = assignments[:parameters] || [nil]*rnd.size
    v = []
    i = 0
    rnd.each do |r|
      self.rounding = r
      v << yield(self, param[i])
      i += 1
    end
  else
    v = yield(self)
  end
  v
  ensure
    set_status s
end
set_status(s) click to toggle source
# File lib/ieee-fpu.rb, line 88
def self.set_status(s)
  Controlfp.call(s,MCW_DN|MCW_EM|MCW_IC|MCW_RC|MCW_PC)
end
supported_precisions() click to toggle source
# File lib/ieee-fpu.rb, line 187
def self.supported_precisions
  [:single, :double, :extended]
end