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


316
317
318
319
# File 'lib/flt/tolerance.rb', line 316

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

Class Method Details

.float_minimum_normalized_fractionObject


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

def self.float_minimum_normalized_fraction
  @float_minimum_normalized_fraction
end

.ref_adjusted_expObject


334
335
336
# File 'lib/flt/tolerance.rb', line 334

def self.ref_adjusted_exp
  -1
end

Instance Method Details

#relative_to_many(mode, *xs) ⇒ Object


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
416
417
418
419
420
# File 'lib/flt/tolerance.rb', line 338

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.new("0.#{digits}E#{vexp+exp}")
    else
      # assert num_class==BigDecimal && @radix==2
      prec = 10
      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


321
322
323
324
325
326
327
# File 'lib/flt/tolerance.rb', line 321

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