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).
- #next_minus(x) ⇒ Object
- #next_plus(x) ⇒ Object
- #next_toward(x, y) ⇒ Object
- #normal?(x) ⇒ Boolean
- #Num(*args) ⇒ Object
- #num_class ⇒ Object
- #pi ⇒ Object
- #plus(x) ⇒ Object
- #precision ⇒ Object
- #radix ⇒ 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.
-
#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:
425 426 427 428 429 |
# File 'lib/flt/float.rb', line 425 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:
412 413 414 415 416 417 418 419 420 421 422 423 |
# File 'lib/flt/float.rb', line 412 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:
431 432 433 434 435 436 437 438 439 440 441 442 |
# File 'lib/flt/float.rb', line 431 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.
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 |
# File 'lib/flt/float.rb', line 386 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
274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'lib/flt/float.rb', line 274 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)
139 140 141 |
# File 'lib/flt/float.rb', line 139 def epsilon(sign=+1) (sign < 0) ? -Float::EPSILON : Float::EPSILON end |
#etiny ⇒ Object
232 233 234 |
# File 'lib/flt/float.rb', line 232 def etiny Float::MIN_EXP - Float::MANT_DIG end |
#etop ⇒ Object
236 237 238 |
# File 'lib/flt/float.rb', line 236 def etop Float::MAX_EXP - Float::MANT_DIG end |
#eval {|_self| ... } ⇒ Object
465 466 467 |
# File 'lib/flt/float.rb', line 465 def eval yield self end |
#exact? ⇒ Boolean
215 216 217 |
# File 'lib/flt/float.rb', line 215 def exact? false end |
#half_epsilon(sign = +1) ⇒ Object
177 178 179 180 181 |
# File 'lib/flt/float.rb', line 177 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
130 131 132 |
# File 'lib/flt/float.rb', line 130 def int_radix_power(n) 1 << n end |
#ln(x) ⇒ Object
457 458 459 |
# File 'lib/flt/float.rb', line 457 def ln(x) log(x) end |
#math(*parameters, &blk) ⇒ Object
469 470 471 472 473 474 475 476 |
# File 'lib/flt/float.rb', line 469 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
207 208 209 |
# File 'lib/flt/float.rb', line 207 def maximum_coefficient int_radix_power(precision)-1 end |
#maximum_finite(sign = +1) ⇒ Object
maximum finite Float value, with specified sign
199 200 201 |
# File 'lib/flt/float.rb', line 199 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)
189 190 191 |
# File 'lib/flt/float.rb', line 189 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
194 195 196 |
# File 'lib/flt/float.rb', line 194 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)
184 185 186 |
# File 'lib/flt/float.rb', line 184 def minimum_normal(sign=+1) (sign < 0) ? -Float::MIN_N : Float::MIN_N end |
#minimum_normalized_coefficient ⇒ Object
211 212 213 |
# File 'lib/flt/float.rb', line 211 def minimum_normalized_coefficient num_class.int_radix_power(precision-1) end |
#minus(x) ⇒ Object
379 380 381 |
# File 'lib/flt/float.rb', line 379 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 |
#next_minus(x) ⇒ Object
244 245 246 |
# File 'lib/flt/float.rb', line 244 def next_minus(x) Flt::FloatContext.neighbours(x).first end |
#next_plus(x) ⇒ Object
240 241 242 |
# File 'lib/flt/float.rb', line 240 def next_plus(x) Flt::FloatContext.neighbours(x).last end |
#next_toward(x, y) ⇒ Object
248 249 250 251 252 253 254 255 256 257 |
# File 'lib/flt/float.rb', line 248 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
359 360 361 362 363 364 365 |
# File 'lib/flt/float.rb', line 359 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 |
#pi ⇒ Object
461 462 463 |
# File 'lib/flt/float.rb', line 461 def pi Math::PI end |
#plus(x) ⇒ Object
375 376 377 |
# File 'lib/flt/float.rb', line 375 def plus(x) x.to_f end |
#precision ⇒ Object
203 204 205 |
# File 'lib/flt/float.rb', line 203 def precision Float::MANT_DIG end |
#rounding ⇒ Object
detect actual rounding mode
220 221 222 |
# File 'lib/flt/float.rb', line 220 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)
260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'lib/flt/float.rb', line 260 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
355 356 357 |
# File 'lib/flt/float.rb', line 355 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
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'lib/flt/float.rb', line 293 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
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/flt/float.rb', line 152 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
367 368 369 370 371 372 373 |
# File 'lib/flt/float.rb', line 367 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.
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/flt/float.rb', line 317 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 |
#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
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/flt/float.rb', line 339 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 |