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:
448 449 450 451 452 |
# File 'lib/flt/float.rb', line 448 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:
435 436 437 438 439 440 441 442 443 444 445 446 |
# File 'lib/flt/float.rb', line 435 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:
454 455 456 457 458 459 460 461 462 463 464 465 |
# File 'lib/flt/float.rb', line 454 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.
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 |
# File 'lib/flt/float.rb', line 409 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
278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/flt/float.rb', line 278 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)
143 144 145 |
# File 'lib/flt/float.rb', line 143 def epsilon(sign=+1) (sign < 0) ? -Float::EPSILON : Float::EPSILON end |
#etiny ⇒ Object
236 237 238 |
# File 'lib/flt/float.rb', line 236 def etiny Float::MIN_EXP - Float::MANT_DIG end |
#etop ⇒ Object
240 241 242 |
# File 'lib/flt/float.rb', line 240 def etop Float::MAX_EXP - Float::MANT_DIG end |
#eval {|_self| ... } ⇒ Object
488 489 490 |
# File 'lib/flt/float.rb', line 488 def eval yield self end |
#exact? ⇒ Boolean
219 220 221 |
# File 'lib/flt/float.rb', line 219 def exact? false end |
#half_epsilon(sign = +1) ⇒ Object
181 182 183 184 185 |
# File 'lib/flt/float.rb', line 181 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
126 127 128 |
# File 'lib/flt/float.rb', line 126 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
134 135 136 |
# File 'lib/flt/float.rb', line 134 def int_radix_power(n) 1 << n end |
#ln(x) ⇒ Object
480 481 482 |
# File 'lib/flt/float.rb', line 480 def ln(x) log(x) end |
#math(*parameters, &blk) ⇒ Object
492 493 494 495 496 497 498 499 |
# File 'lib/flt/float.rb', line 492 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
211 212 213 |
# File 'lib/flt/float.rb', line 211 def maximum_coefficient int_radix_power(precision)-1 end |
#maximum_finite(sign = +1) ⇒ Object
maximum finite Float value, with specified sign
203 204 205 |
# File 'lib/flt/float.rb', line 203 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)
193 194 195 |
# File 'lib/flt/float.rb', line 193 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
198 199 200 |
# File 'lib/flt/float.rb', line 198 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)
188 189 190 |
# File 'lib/flt/float.rb', line 188 def minimum_normal(sign=+1) (sign < 0) ? -Float::MIN_N : Float::MIN_N end |
#minimum_normalized_coefficient ⇒ Object
215 216 217 |
# File 'lib/flt/float.rb', line 215 def minimum_normalized_coefficient num_class.int_radix_power(precision-1) end |
#minus(x) ⇒ Object
383 384 385 |
# File 'lib/flt/float.rb', line 383 def minus(x) -x.to_f end |
#nan ⇒ Object
NaN (not a number value)
116 117 118 |
# File 'lib/flt/float.rb', line 116 def nan 0.0/0.0 # Ruby 1.9.2: Float::NAN end |
#necessary_digits(b) ⇒ Object
511 512 513 514 515 516 517 518 519 |
# File 'lib/flt/float.rb', line 511 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
248 249 250 |
# File 'lib/flt/float.rb', line 248 def next_minus(x) Flt::FloatContext.neighbours(x).first end |
#next_plus(x) ⇒ Object
244 245 246 |
# File 'lib/flt/float.rb', line 244 def next_plus(x) Flt::FloatContext.neighbours(x).last end |
#next_toward(x, y) ⇒ Object
252 253 254 255 256 257 258 259 260 261 |
# File 'lib/flt/float.rb', line 252 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
363 364 365 366 367 368 369 |
# File 'lib/flt/float.rb', line 363 def normal?(x) if x.special? || x.zero? false else x.abs >= Float::MIN_N end end |
#Num(*args) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/flt/float.rb', line 99 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
130 131 132 |
# File 'lib/flt/float.rb', line 130 def one_half 0.5 end |
#pi ⇒ Object
484 485 486 |
# File 'lib/flt/float.rb', line 484 def pi Math::PI end |
#plus(x) ⇒ Object
379 380 381 |
# File 'lib/flt/float.rb', line 379 def plus(x) x.to_f end |
#precision ⇒ Object
207 208 209 |
# File 'lib/flt/float.rb', line 207 def precision Float::MANT_DIG end |
#rationalize(x, tol = Flt.Tolerance(:epsilon), strict = false) ⇒ Object
391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
# File 'lib/flt/float.rb', line 391 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
501 502 503 504 505 506 507 508 509 |
# File 'lib/flt/float.rb', line 501 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
224 225 226 |
# File 'lib/flt/float.rb', line 224 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)
264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/flt/float.rb', line 264 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
359 360 361 |
# File 'lib/flt/float.rb', line 359 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
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/flt/float.rb', line 297 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
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/flt/float.rb', line 156 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
371 372 373 374 375 376 377 |
# File 'lib/flt/float.rb', line 371 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.
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
# File 'lib/flt/float.rb', line 321 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
387 388 389 |
# File 'lib/flt/float.rb', line 387 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
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
# File 'lib/flt/float.rb', line 343 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
121 122 123 |
# File 'lib/flt/float.rb', line 121 def zero(sign=+1) (sign < 0) ? -0.0 : 0.0 end |