Class: Flt::FloatingTolerance

Inherits:
Tolerance show all
Defined in:
lib/flt/tolerance.rb

Overview

Implementation of floating tolerances

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Tolerance

#[], big_epsilon, bits, #cast_value, decimals, define_sugar, #descr_value, digits, epsilon, #eq?, #equal_to?, #greater_than?, #gt?, #integer, #integer?, #less_than?, #lt?, #relative_to, #seq?, #value, #zero?

Constructor Details

#initialize(value, radix = :native) ⇒ FloatingTolerance

Returns a new instance of FloatingTolerance.


312
313
314
315
# File 'lib/flt/tolerance.rb', line 312

def initialize(value, radix=:native)
  super(value)
  @radix = radix
end

Class Method Details

.float_minimum_normalized_fractionObject


326
327
328
# File 'lib/flt/tolerance.rb', line 326

def self.float_minimum_normalized_fraction
  @float_minimum_normalized_fraction
end

.ref_adjusted_expObject


330
331
332
# File 'lib/flt/tolerance.rb', line 330

def self.ref_adjusted_exp
  -1
end

Instance Method Details

#relative_to_many(mode, *xs) ⇒ Object


334
335
336
337
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
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
# File 'lib/flt/tolerance.rb', line 334

def relative_to_many(mode, *xs)
  exp = nil

  num_class = xs.first.class
  context = num_class.context
  xs = xs.map{|x| x = context.Num(x); x.zero? ? context.minimum_normal(context.sign(x)) : x}
  v = cast_value(num_class)

  # TODO: simplify using context
  case xs.first
  when Flt::Num
    # TODO: handle special values
    if @radix == :native || @radix == num_class.radix
      exp = xs.map do |x|
        x = x.normalize
        exp = x.adjusted_exponent
        exp -= 1 if x.coefficient == x.num_class.context.minimum_normalized_coefficient # if :low mode
        exp -= FloatingTolerance.ref_adjusted_exp
        exp
      end.send(mode)
      r = num_class.Num(+1, v.coefficient, v.exponent+exp)
      r = r.normalize if num_class.radix == 2
      r
    elsif @radix==10
      # assert x.class==BinNum
      # TODO: optimize (implement log10 for BinNum)
      exp = xs.map do |x|
        x = x.to_decimal_exact(:exact=>true).normalize
        exp = x.adjusted_exponent
        exp -= 1 if x.coefficient == x.num_class.context.minimum_normalized_coefficient # if :low mode
        exp -= FloatingTolerance.ref_adjusted_exp
        exp
      end.send(mode)
      num_class.from_decimal(Flt.DecNum(+1, 1, exp)*v.to_decimal_exact)
    else
      # assert num_class==DecNum && @radix==2
      exp = xs.map do |x|
        exp = (x.ln/DecNum(2).ln).ceil.to_i - 1 # (x.ln/DecNum(2).ln).floor+1 - 1 if :high mode
        exp -= FloatingTolerance.ref_adjusted_exp
        exp
      end.send(mode)
      v*num_class.Num(2)**exp
    end
  when Float
    if @radix == :native || @radix == Float::RADIX
      exp = xs.map do |x|
        f,e = Math.frexp(x)
        exp = e-1
        exp -= 1 if f==FloatingTolerance.float_minimum_normalized_fraction # if :low mode
        exp -= FloatingTolerance.ref_adjusted_exp
      end.send(mode)
      Math.ldexp(v.to_f, exp)
    else
      # assert @radix==10
      exp = xs.map do |x|
        exp = Math.log10(x.abs).ceil - 1 # Math.log10(x.abs).floor+1 - 1 if :high mode
        exp -= FloatingTolerance.ref_adjusted_exp
      end.send(mode)
      v*10.0**exp
    end
  when BigDecimal
    if @radix == :native || @radix == 10
      exp = xs.map do |x|
        _sign,digits,_base,exp = x.split
        exp -= 1
        exp -= 1 if digits=="1" # if :low mode
        exp -= FloatingTolerance.ref_adjusted_exp
        exp
      end.send(mode)
      _sign, digits, _base, vexp = v.split
      BigDecimal("0.#{digits}E#{vexp+exp}")
    else
      # assert num_class==BigDecimal && @radix==2
      exp = xs.map do |x|
        exp = (Flt::DecNum(x.to_s).ln/Flt::DecNum(2).ln).ceil - 1 # ... if :high mode
        exp -= FloatingTolerance.ref_adjusted_exp
        exp
      end.send(mode)
      context.Num(v)*context.Num(2)**exp
    end
  end
end

#to_sObject


317
318
319
320
321
322
323
# File 'lib/flt/tolerance.rb', line 317

def to_s
  if @radix==:native
    "#{descr_value} flt."
  else
    "#{descr_value} flt.(#{radix})"
  end
end