Class: Flt::FloatContext
Overview
Context class with some of the Flt::Num context functionality, to allow the use of Float numbers similarly to other Num values; this eases the implementation of functions compatible with either Num or Float values.
Class Method Summary collapse
-
.float_binary_operator(method, op) ⇒ Object
:nodoc:.
-
.float_method(*methods) ⇒ Object
:nodoc:.
-
.math_function(*methods) ⇒ Object
:nodoc:.
-
.neighbours(x) ⇒ Object
Compute the adjacent floating point values: largest value not larger than this and smallest not smaller.
Instance Method Summary collapse
-
#copy_sign(x, y) ⇒ Object
Return copy of x with the sign of y.
- #emax ⇒ Object
- #emin ⇒ Object
-
#epsilon(sign = +1) ⇒ Object
This is the difference between 1.0 and the smallest floating-point value greater than 1.0, radix_power(1-significand_precision).
- #etiny ⇒ Object
- #etop ⇒ Object
- #eval {|_self| ... } ⇒ Object
- #exact? ⇒ Boolean
-
#half_epsilon(sign = +1) ⇒ Object
This is the maximum relative error corresponding to 1/2 ulp: (radix/2)*radix_power(-significand_precision) == epsilon/2 This is called “machine epsilon” in [Goldberg] We have:.
-
#infinity(sign = +1) ⇒ Object
infinity value with specified sign.
- #int_radix_power(n) ⇒ Object
- #ln(x) ⇒ Object
- #math(*parameters, &blk) ⇒ Object
- #maximum_coefficient ⇒ Object
-
#maximum_finite(sign = +1) ⇒ Object
maximum finite Float value, with specified sign.
-
#maximum_subnormal(sign = +1) ⇒ Object
maximum subnormal (denormalized) Float value (with specified sign).
-
#minimum_nonzero(sign = +1) ⇒ Object
minimum (subnormal) nonzero Float value, with specified sign.
-
#minimum_normal(sign = +1) ⇒ Object
minimum normal Float value (with specified sign).
- #minimum_normalized_coefficient ⇒ Object
- #minus(x) ⇒ Object
-
#nan ⇒ Object
NaN (not a number value).
- #necessary_digits(b) ⇒ Object
- #next_minus(x) ⇒ Object
- #next_plus(x) ⇒ Object
- #next_toward(x, y) ⇒ Object
- #normal?(x) ⇒ Boolean
- #Num(*args) ⇒ Object
- #num_class ⇒ Object
- #one_half ⇒ Object
- #pi ⇒ Object
- #plus(x) ⇒ Object
- #precision ⇒ Object
- #radix ⇒ Object
- #rationalize(x, tol = Flt.Tolerance(:epsilon), strict = false) ⇒ Object
- #representable_digits(b) ⇒ Object
-
#rounding ⇒ Object
detect actual rounding mode.
-
#sign(x) ⇒ Object
Sign: -1 for minus, +1 for plus, nil for nan (note that Float zero is signed).
- #special?(x) ⇒ Boolean
-
#split(x) ⇒ Object
Returns the internal representation of the number, composed of: * a sign which is +1 for plus and -1 for minus * a coefficient (significand) which is a nonnegative integer * an exponent (an integer) or :inf, :nan or :snan for special values The value of non-special numbers is sign*coefficient*10^exponent.
-
#strict_epsilon(sign = +1, round = nil) ⇒ Object
The strict epsilon is the smallest value that produces something different from 1.0 wehen added to 1.0.
- #subnormal? ⇒ Boolean
-
#to_int_scale(x) ⇒ Object
Return the value of the number as an signed integer and a scale.
- #to_r(x) ⇒ Object
-
#ulp(x, mode = :low) ⇒ Object
ulp (unit in the last place) according to the definition proposed by J.M.
-
#zero(sign = +1) ⇒ Object
zero value with specified sign.
Class Method Details
.float_binary_operator(method, op) ⇒ Object
:nodoc:
446 447 448 449 450 |
# File 'lib/flt/float.rb', line 446 def float_binary_operator(method, op) #:nodoc: define_method(method) do |x,y| x.to_f.send(op,y) end end |
.float_method(*methods) ⇒ Object
:nodoc:
433 434 435 436 437 438 439 440 441 442 443 444 |
# File 'lib/flt/float.rb', line 433 def float_method(*methods) #:nodoc: methods.each do |method| if method.is_a?(Array) float_method, context_method = method else float_method = context_method = method end define_method(context_method) do |x| x.to_f.send float_method end end end |
.math_function(*methods) ⇒ Object
:nodoc:
452 453 454 455 456 457 458 459 460 461 462 463 |
# File 'lib/flt/float.rb', line 452 def math_function(*methods) #:nodoc: methods.each do |method| define_method(method) do |*args| x = args.shift.to_f Math.send(method, x, *args) end # TODO: consider injecting the math methods into Float # Float.send(:define_method, method) do |*args| # Math.send(method, self, *args) # end end end |
.neighbours(x) ⇒ Object
Compute the adjacent floating point values: largest value not larger than this and smallest not smaller.
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'lib/flt/float.rb', line 407 def neighbours(x) f,e = Math.frexp(x.to_f) e = Float::MIN_EXP if f==0 e = [Float::MIN_EXP,e].max dx = Math.ldexp(1,e-Float::MANT_DIG) #Math.ldexp(Math.ldexp(1.0,-Float::MANT_DIG),e) min_f = 0.5 #0.5==Math.ldexp(2**(bits-1),-Float::MANT_DIG) max_f = 1.0 - Math.ldexp(1,-Float::MANT_DIG) if f==max_f high = x + dx*2 elsif f==-min_f && e!=Float::MIN_EXP high = x + dx/2 else high = x + dx end if e==Float::MIN_EXP || f!=min_f low = x - dx elsif f==-max_f high = x - dx*2 else low = x - dx/2 end [low, high] end |
Instance Method Details
#copy_sign(x, y) ⇒ Object
Return copy of x with the sign of y
276 277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'lib/flt/float.rb', line 276 def copy_sign(x, y) self_sign = sign(x) other_sign = y.is_a?(Integer) ? (y < 0 ? -1 : +1) : sign(y) if self_sign && other_sign if self_sign == other_sign x.to_f else -x.to_f end else nan end end |
#epsilon(sign = +1) ⇒ Object
This is the difference between 1.0 and the smallest floating-point value greater than 1.0, radix_power(1-significand_precision)
We have:
Float.epsilon == (1.0.next-1.0)
141 142 143 |
# File 'lib/flt/float.rb', line 141 def epsilon(sign=+1) (sign < 0) ? -Float::EPSILON : Float::EPSILON end |
#etiny ⇒ Object
234 235 236 |
# File 'lib/flt/float.rb', line 234 def etiny Float::MIN_EXP - Float::MANT_DIG end |
#etop ⇒ Object
238 239 240 |
# File 'lib/flt/float.rb', line 238 def etop Float::MAX_EXP - Float::MANT_DIG end |
#eval {|_self| ... } ⇒ Object
486 487 488 |
# File 'lib/flt/float.rb', line 486 def eval yield self end |
#exact? ⇒ Boolean
217 218 219 |
# File 'lib/flt/float.rb', line 217 def exact? false end |
#half_epsilon(sign = +1) ⇒ Object
179 180 181 182 183 |
# File 'lib/flt/float.rb', line 179 def half_epsilon(sign=+1) # 0.5*epsilon(sign) f,e = Math.frexp(1) Math.ldexp(f, e-Float::MANT_DIG) end |
#infinity(sign = +1) ⇒ Object
infinity value with specified sign
124 125 126 |
# File 'lib/flt/float.rb', line 124 def infinity(sign=+1) (sign < 0) ? -1.0/0.0 : 1.0/0.0 # Ruby 1.9.2: (sing < 0) ? -Float::INFINITY : Float::INFINITY end |
#int_radix_power(n) ⇒ Object
132 133 134 |
# File 'lib/flt/float.rb', line 132 def int_radix_power(n) 1 << n end |
#ln(x) ⇒ Object
478 479 480 |
# File 'lib/flt/float.rb', line 478 def ln(x) log(x) end |
#math(*parameters, &blk) ⇒ Object
490 491 492 493 494 495 496 497 |
# File 'lib/flt/float.rb', line 490 def math(*parameters, &blk) if parameters.empty? self.instance_eval(&blk) else # needs instance_exe (available in Ruby 1.9, ActiveRecord; TODO: include implementation here) self.instance_exec(*parameters, &blk) end end |
#maximum_coefficient ⇒ Object
209 210 211 |
# File 'lib/flt/float.rb', line 209 def maximum_coefficient int_radix_power(precision)-1 end |
#maximum_finite(sign = +1) ⇒ Object
maximum finite Float value, with specified sign
201 202 203 |
# File 'lib/flt/float.rb', line 201 def maximum_finite(sign=+1) (sign < 0) ? -Float::MAX : Float::MAX end |
#maximum_subnormal(sign = +1) ⇒ Object
maximum subnormal (denormalized) Float value (with specified sign)
191 192 193 |
# File 'lib/flt/float.rb', line 191 def maximum_subnormal(sign=+1) (sign < 0) ? -Float::MAX_D : Float::MAX_D end |
#minimum_nonzero(sign = +1) ⇒ Object
minimum (subnormal) nonzero Float value, with specified sign
196 197 198 |
# File 'lib/flt/float.rb', line 196 def minimum_nonzero(sign=+1) (sign < 0) ? -Float::MIN_D : Float::MIN_D end |
#minimum_normal(sign = +1) ⇒ Object
minimum normal Float value (with specified sign)
186 187 188 |
# File 'lib/flt/float.rb', line 186 def minimum_normal(sign=+1) (sign < 0) ? -Float::MIN_N : Float::MIN_N end |
#minimum_normalized_coefficient ⇒ Object
213 214 215 |
# File 'lib/flt/float.rb', line 213 def minimum_normalized_coefficient num_class.int_radix_power(precision-1) end |
#minus(x) ⇒ Object
381 382 383 |
# File 'lib/flt/float.rb', line 381 def minus(x) -x.to_f end |
#nan ⇒ Object
NaN (not a number value)
114 115 116 |
# File 'lib/flt/float.rb', line 114 def nan 0.0/0.0 # Ruby 1.9.2: Float::NAN end |
#necessary_digits(b) ⇒ Object
509 510 511 512 513 514 515 516 517 |
# File 'lib/flt/float.rb', line 509 def necessary_digits(b) if b == 10 Float::DECIMAL_DIG elsif b == radix precision else (precision*log(radix, b)).ceil + 1 end end |
#next_minus(x) ⇒ Object
246 247 248 |
# File 'lib/flt/float.rb', line 246 def next_minus(x) Flt::FloatContext.neighbours(x).first end |
#next_plus(x) ⇒ Object
242 243 244 |
# File 'lib/flt/float.rb', line 242 def next_plus(x) Flt::FloatContext.neighbours(x).last end |
#next_toward(x, y) ⇒ Object
250 251 252 253 254 255 256 257 258 259 |
# File 'lib/flt/float.rb', line 250 def next_toward(x, y) x, y = x.to_f, y.to_f comparison = x <=> y return x.copy_sign(y) if comparison == 0 if comparison == -1 result = x.next_plus(context) else # comparison == 1 result = x.next_minus(context) end end |
#normal?(x) ⇒ Boolean
361 362 363 364 365 366 367 |
# File 'lib/flt/float.rb', line 361 def normal?(x) if x.special? || x.zero? false else x.abs >= Float::MIN_N end end |
#Num(*args) ⇒ Object
97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/flt/float.rb', line 97 def Num(*args) args.flatten! case args.size when 1 Float(*args) when 2 Math.ldexp(args[0],args[1]) when 3 Math.ldexp(args[0]*args[1],args[2]) end end |
#one_half ⇒ Object
128 129 130 |
# File 'lib/flt/float.rb', line 128 def one_half 0.5 end |
#pi ⇒ Object
482 483 484 |
# File 'lib/flt/float.rb', line 482 def pi Math::PI end |
#plus(x) ⇒ Object
377 378 379 |
# File 'lib/flt/float.rb', line 377 def plus(x) x.to_f end |
#precision ⇒ Object
205 206 207 |
# File 'lib/flt/float.rb', line 205 def precision Float::MANT_DIG end |
#rationalize(x, tol = Flt.Tolerance(:epsilon), strict = false) ⇒ Object
389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/flt/float.rb', line 389 def rationalize(x, tol = Flt.Tolerance(:epsilon), strict=false) if !strict && x.respond_to?(:rationalize) && !(Integer === tol) # Float#rationalize was introduced in Ruby 1.9.1 tol = Tolerance(tol) x.rationalize(tol[x]) else case tol when Integer Rational(*Support::Rationalizer.max_denominator(x, tol, Float)) else Rational(*Support::Rationalizer[tol].rationalize(x)) end end end |
#representable_digits(b) ⇒ Object
499 500 501 502 503 504 505 506 507 |
# File 'lib/flt/float.rb', line 499 def representable_digits(b) if b == 10 Float::DIG elsif b == radix precision else ((precision-1)*log(radix, b)).floor end end |
#rounding ⇒ Object
detect actual rounding mode
222 223 224 |
# File 'lib/flt/float.rb', line 222 def rounding Flt::Support::AuxiliarFunctions.detect_float_rounding end |
#sign(x) ⇒ Object
Sign: -1 for minus, +1 for plus, nil for nan (note that Float zero is signed)
262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/flt/float.rb', line 262 def sign(x) x = x.to_f if x.nan? nil elsif x.zero? # Note that (x.to_s[0,1] == "-" ? -1 : +1) fails under mswin32 # because in that platform (-0.0).to_s == '0.0' (1/x < 0) ? -1 : +1 else x < 0 ? -1 : +1 end end |
#special?(x) ⇒ Boolean
357 358 359 |
# File 'lib/flt/float.rb', line 357 def special?(x) x.nan? || x.infinite? end |
#split(x) ⇒ Object
Returns the internal representation of the number, composed of:
-
a sign which is +1 for plus and -1 for minus
-
a coefficient (significand) which is a nonnegative integer
-
an exponent (an integer) or :inf, :nan or :snan for special values
The value of non-special numbers is sign*coefficient*10^exponent
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/flt/float.rb', line 295 def split(x) x = x.to_f sign = sign(x) if x.nan? exp = :nan elsif x.infinite? exp = :inf else coeff,exp = Math.frexp(x) coeff = coeff.abs if exp < Float::MIN_EXP # denormalized number coeff = Math.ldexp(coeff, exp-Float::MIN_EXP+Float::MANT_DIG).to_i exp = Float::MIN_EXP-Float::MANT_DIG else # normalized number coeff = Math.ldexp(coeff, Float::MANT_DIG).to_i exp -= Float::MANT_DIG end end [sign, coeff, exp] end |
#strict_epsilon(sign = +1, round = nil) ⇒ Object
The strict epsilon is the smallest value that produces something different from 1.0 wehen added to 1.0. It may be smaller than the general epsilon, because of the particular rounding rules used with the floating point format. This is only meaningful when well-defined rules are used for rounding the result of floating-point addition.
We have:
(Float.strict_epsilon+1.0) == 1.0.next
(Float.strict_epsilon.prev+1.0) == 1.0
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/flt/float.rb', line 154 def strict_epsilon(sign=+1, round=nil) # We don't rely on Float::ROUNDS eps = minimum_nonzero unless (1.0+eps) > 1.0 f,e = Math.frexp(1) eps = Math.ldexp(f.next,e-Float::MANT_DIG) if (1.0+eps) > 1.0 eps else eps = Math.ldexp(f,e-Float::MANT_DIG) unless (1.0+eps) > 1.0 else eps = Math.ldexp(f,e-Float::MANT_DIG+1) end end end eps end |
#subnormal? ⇒ Boolean
369 370 371 372 373 374 375 |
# File 'lib/flt/float.rb', line 369 def subnormal? if x.special? || x.zero? false else x.abs < Float::MIN_N end end |
#to_int_scale(x) ⇒ Object
Return the value of the number as an signed integer and a scale.
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/flt/float.rb', line 319 def to_int_scale(x) x = x.to_f if special?(x) nil else coeff,exp = Math.frexp(x) coeff = coeff if exp < Float::MIN_EXP # denormalized number coeff = Math.ldexp(coeff, exp-Float::MIN_EXP+Float::MANT_DIG).to_i exp = Float::MIN_EXP-Float::MANT_DIG else # normalized number coeff = Math.ldexp(coeff, Float::MANT_DIG).to_i exp -= Float::MANT_DIG end [coeff, exp] end end |
#to_r(x) ⇒ Object
385 386 387 |
# File 'lib/flt/float.rb', line 385 def to_r(x) Support::Rationalizer.to_r(x) end |
#ulp(x, mode = :low) ⇒ Object
ulp (unit in the last place) according to the definition proposed by J.M. Muller in “On the definition of ulp(x)” INRIA No. 5504
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
# File 'lib/flt/float.rb', line 341 def ulp(x, mode=:low) x = x.to_f return x if x.nan? x = x.abs if x < Math.ldexp(1,Float::MIN_EXP) # x < Float::RADIX*Float::MIN_N x = Math.ldexp(1,Float::MIN_EXP-Float::MANT_DIG) # res = Float::MIN_D elsif x > Float::MAX # x > Math.ldexp(1-Math.ldexp(1,-Float::MANT_DIG),Float::MAX_EXP) x = Math.ldexp(1,Float::MAX_EXP-Float::MANT_DIG) # res = Float::MAX - Float::MAX.prev else f,e = Math.frexp(x.to_f) e -= 1 if f==Math.ldexp(1,-1) if mode==:low # assign the smaller ulp to radix powers x = Math.ldexp(1,e-Float::MANT_DIG) end x end |
#zero(sign = +1) ⇒ Object
zero value with specified sign
119 120 121 |
# File 'lib/flt/float.rb', line 119 def zero(sign=+1) (sign < 0) ? -0.0 : 0.0 end |