mirror of
https://github.com/mistergibson/gxg-web-client.git
synced 2026-08-15 11:34:29 -07:00
602 lines
10 KiB
Ruby
602 lines
10 KiB
Ruby
class Float < Numeric
|
|
def **(other)
|
|
Rubinius.primitive :float_pow
|
|
|
|
if other.is_a?(Float) && self < 0 && other != other.round
|
|
return Complex.new(self, 0) ** other
|
|
end
|
|
|
|
b, a = math_coerce other
|
|
a ** b
|
|
end
|
|
|
|
def imaginary
|
|
0
|
|
end
|
|
|
|
def numerator
|
|
if nan?
|
|
NAN
|
|
elsif infinite? == 1
|
|
INFINITY
|
|
elsif infinite? == -1
|
|
-INFINITY
|
|
else
|
|
super
|
|
end
|
|
end
|
|
|
|
def denominator
|
|
if infinite? || nan?
|
|
1
|
|
else
|
|
super
|
|
end
|
|
end
|
|
|
|
def to_r
|
|
f, e = Math.frexp self
|
|
f = Math.ldexp(f, MANT_DIG).to_i
|
|
e -= MANT_DIG
|
|
|
|
(f * (RADIX ** e)).to_r
|
|
end
|
|
|
|
def arg
|
|
if nan?
|
|
self
|
|
elsif signbit?
|
|
Math::PI
|
|
else
|
|
0
|
|
end
|
|
end
|
|
alias_method :angle, :arg
|
|
alias_method :phase, :arg
|
|
|
|
def rationalize(eps=undefined)
|
|
if undefined.equal?(eps)
|
|
f, n = Math.frexp self
|
|
f = Math.ldexp(f, Float::MANT_DIG).to_i
|
|
n -= Float::MANT_DIG
|
|
|
|
Rational.new(2 * f, 1 << (1 - n)).rationalize(Rational.new(1, 1 << (1 - n)))
|
|
else
|
|
to_r.rationalize(eps)
|
|
end
|
|
end
|
|
|
|
def round(ndigits=0)
|
|
ndigits = Rubinius::Type.coerce_to(ndigits, Integer, :to_int)
|
|
|
|
if ndigits == 0
|
|
return Rubinius.invoke_primitive :float_round, self
|
|
elsif ndigits < 0
|
|
return truncate.round ndigits
|
|
end
|
|
|
|
return self if infinite? or nan?
|
|
|
|
_, exp = Math.frexp(self)
|
|
|
|
if ndigits >= (Float::DIG + 2) - (exp > 0 ? exp / 4 : exp / 3 - 1)
|
|
return self
|
|
end
|
|
|
|
if ndigits < -(exp > 0 ? exp / 3 + 1 : exp / 4)
|
|
return 0.0
|
|
end
|
|
|
|
f = 10**ndigits
|
|
Rubinius.invoke_primitive(:float_round, self * f) / f.to_f
|
|
end
|
|
def coerce(other)
|
|
return [other, self] if other.kind_of? Float
|
|
[Float(other), self]
|
|
end
|
|
|
|
def -@
|
|
Rubinius.primitive :float_neg
|
|
raise PrimitiveFailure, "Float#-@ primitive failed"
|
|
end
|
|
|
|
def abs
|
|
FFI::Platform::Math.fabs(self)
|
|
end
|
|
|
|
alias_method :magnitude, :abs
|
|
|
|
def signbit?
|
|
Rubinius.primitive :float_signbit_p
|
|
raise PrimitiveFailure, "Float#signbit? primitive failed"
|
|
end
|
|
|
|
def +(other)
|
|
Rubinius.asm do
|
|
flt = new_label
|
|
done = new_label
|
|
|
|
r0 = new_register
|
|
r1 = new_register
|
|
r2 = new_register
|
|
r3 = new_register
|
|
|
|
r_load_m_binops r0, r1
|
|
|
|
n_promote r2, r0, r1
|
|
|
|
r_load_1 r3
|
|
n_ieq r3, r3, r2
|
|
b_if r3, flt
|
|
goto done
|
|
|
|
flt.set!
|
|
n_dadd r0, r0, r1
|
|
r_store_float r0, r0
|
|
r_ret r0
|
|
|
|
done.set!
|
|
|
|
# TODO: teach the bytecode compiler better
|
|
push_true
|
|
end
|
|
|
|
b, a = math_coerce other
|
|
a + b
|
|
end
|
|
|
|
def -(other)
|
|
Rubinius.asm do
|
|
flt = new_label
|
|
done = new_label
|
|
|
|
r0 = new_register
|
|
r1 = new_register
|
|
r2 = new_register
|
|
r3 = new_register
|
|
|
|
r_load_m_binops r0, r1
|
|
|
|
n_promote r2, r0, r1
|
|
|
|
r_load_1 r3
|
|
n_ieq r3, r3, r2
|
|
b_if r3, flt
|
|
goto done
|
|
|
|
flt.set!
|
|
n_dsub r0, r0, r1
|
|
r_store_float r0, r0
|
|
r_ret r0
|
|
|
|
done.set!
|
|
|
|
# TODO: teach the bytecode compiler better
|
|
push_true
|
|
end
|
|
|
|
b, a = math_coerce other
|
|
a - b
|
|
end
|
|
|
|
def *(other)
|
|
Rubinius.asm do
|
|
flt = new_label
|
|
done = new_label
|
|
|
|
r0 = new_register
|
|
r1 = new_register
|
|
r2 = new_register
|
|
r3 = new_register
|
|
|
|
r_load_m_binops r0, r1
|
|
|
|
n_promote r2, r0, r1
|
|
|
|
r_load_1 r3
|
|
n_ieq r3, r3, r2
|
|
b_if r3, flt
|
|
goto done
|
|
|
|
flt.set!
|
|
n_dmul r0, r0, r1
|
|
r_store_float r0, r0
|
|
r_ret r0
|
|
|
|
done.set!
|
|
|
|
# TODO: teach the bytecode compiler better
|
|
push_true
|
|
end
|
|
|
|
b, a = math_coerce other
|
|
a * b
|
|
end
|
|
|
|
def /(other)
|
|
Rubinius.asm do
|
|
flt = new_label
|
|
done = new_label
|
|
|
|
r0 = new_register
|
|
r1 = new_register
|
|
r2 = new_register
|
|
r3 = new_register
|
|
|
|
r_load_m_binops r0, r1
|
|
|
|
n_promote r2, r0, r1
|
|
|
|
r_load_1 r3
|
|
n_ieq r3, r3, r2
|
|
b_if r3, flt
|
|
goto done
|
|
|
|
flt.set!
|
|
n_ddiv r0, r0, r1
|
|
r_store_float r0, r0
|
|
r_ret r0
|
|
|
|
done.set!
|
|
|
|
# TODO: teach the bytecode compiler better
|
|
push_true
|
|
end
|
|
|
|
redo_coerced :/, other
|
|
end
|
|
|
|
alias_method :divide, :/
|
|
alias_method :quo, :/
|
|
alias_method :fdiv, :/
|
|
|
|
INFINITY = 1.0 / 0.0
|
|
NAN = 0.0 / 0.0
|
|
|
|
def divmod(other)
|
|
Rubinius.primitive :float_divmod
|
|
b, a = math_coerce other
|
|
a.divmod b
|
|
end
|
|
|
|
def %(other)
|
|
return 0 / 0.to_f if other == 0
|
|
Rubinius.primitive :float_mod
|
|
b, a = math_coerce other
|
|
a % b
|
|
end
|
|
|
|
alias_method :modulo, :%
|
|
|
|
def <(other)
|
|
Rubinius.asm do
|
|
done = new_label
|
|
|
|
r0 = new_register
|
|
r1 = new_register
|
|
r2 = new_register
|
|
r3 = new_register
|
|
|
|
r_load_m_binops r0, r1
|
|
|
|
n_promote r2, r0, r1
|
|
|
|
r_load_0 r3
|
|
n_ieq r3, r3, r2
|
|
b_if r3, done
|
|
|
|
n_dlt r0, r0, r1
|
|
r_load_bool r0, r0
|
|
r_ret r0
|
|
|
|
done.set!
|
|
|
|
# TODO: teach the bytecode compiler better
|
|
push_true
|
|
end
|
|
|
|
b, a = math_coerce other, :compare_error
|
|
a < b
|
|
end
|
|
|
|
def <=(other)
|
|
Rubinius.asm do
|
|
done = new_label
|
|
|
|
r0 = new_register
|
|
r1 = new_register
|
|
r2 = new_register
|
|
r3 = new_register
|
|
|
|
r_load_m_binops r0, r1
|
|
|
|
n_promote r2, r0, r1
|
|
|
|
r_load_0 r3
|
|
n_ieq r3, r3, r2
|
|
b_if r3, done
|
|
|
|
n_dle r0, r0, r1
|
|
r_load_bool r0, r0
|
|
r_ret r0
|
|
|
|
done.set!
|
|
|
|
# TODO: teach the bytecode compiler better
|
|
push_true
|
|
end
|
|
|
|
b, a = math_coerce other, :compare_error
|
|
a <= b
|
|
end
|
|
|
|
def >(other)
|
|
Rubinius.asm do
|
|
done = new_label
|
|
|
|
r0 = new_register
|
|
r1 = new_register
|
|
r2 = new_register
|
|
r3 = new_register
|
|
|
|
r_load_m_binops r0, r1
|
|
|
|
n_promote r2, r0, r1
|
|
|
|
r_load_0 r3
|
|
n_ieq r3, r3, r2
|
|
b_if r3, done
|
|
|
|
n_dgt r0, r0, r1
|
|
r_load_bool r0, r0
|
|
r_ret r0
|
|
|
|
done.set!
|
|
|
|
# TODO: teach the bytecode compiler better
|
|
push_true
|
|
end
|
|
|
|
b, a = math_coerce other, :compare_error
|
|
a > b
|
|
end
|
|
|
|
def >=(other)
|
|
Rubinius.asm do
|
|
done = new_label
|
|
|
|
r0 = new_register
|
|
r1 = new_register
|
|
r2 = new_register
|
|
r3 = new_register
|
|
|
|
r_load_m_binops r0, r1
|
|
|
|
n_promote r2, r0, r1
|
|
|
|
r_load_0 r3
|
|
n_ieq r3, r3, r2
|
|
b_if r3, done
|
|
|
|
n_dge r0, r0, r1
|
|
r_load_bool r0, r0
|
|
r_ret r0
|
|
|
|
done.set!
|
|
|
|
# TODO: teach the bytecode compiler better
|
|
push_true
|
|
end
|
|
|
|
b, a = math_coerce other, :compare_error
|
|
a >= b
|
|
end
|
|
|
|
def <=>(other)
|
|
Rubinius.primitive :float_compare
|
|
b, a = math_coerce other, :compare_error
|
|
a <=> b
|
|
rescue ArgumentError
|
|
nil
|
|
end
|
|
|
|
def !=(other)
|
|
Rubinius.asm do
|
|
done = new_label
|
|
|
|
r0 = new_register
|
|
r1 = new_register
|
|
r2 = new_register
|
|
r3 = new_register
|
|
|
|
r_load_m_binops r0, r1
|
|
|
|
n_promote r2, r0, r1
|
|
|
|
r_load_0 r3
|
|
n_ieq r3, r3, r2
|
|
b_if r3, done
|
|
|
|
n_dne r0, r0, r1
|
|
r_load_bool r0, r0
|
|
r_ret r0
|
|
|
|
done.set!
|
|
|
|
# TODO: teach the bytecode compiler better
|
|
push_true
|
|
end
|
|
|
|
b, a = math_coerce(other)
|
|
a != b ? true : false
|
|
end
|
|
|
|
def ==(other)
|
|
Rubinius.asm do
|
|
done = new_label
|
|
|
|
r0 = new_register
|
|
r1 = new_register
|
|
r2 = new_register
|
|
r3 = new_register
|
|
|
|
r_load_m_binops r0, r1
|
|
|
|
n_promote r2, r0, r1
|
|
|
|
r_load_0 r3
|
|
n_ieq r3, r3, r2
|
|
b_if r3, done
|
|
|
|
n_deq r0, r0, r1
|
|
r_load_bool r0, r0
|
|
r_ret r0
|
|
|
|
done.set!
|
|
|
|
# TODO: teach the bytecode compiler better
|
|
push_true
|
|
end
|
|
|
|
begin
|
|
b, a = math_coerce(other)
|
|
a == b ? true : false
|
|
rescue TypeError
|
|
return other == self
|
|
end
|
|
end
|
|
|
|
def eql?(other)
|
|
Rubinius.primitive :float_eql
|
|
false
|
|
end
|
|
|
|
def nan?
|
|
Rubinius.asm do
|
|
r0 = new_register
|
|
r1 = new_register
|
|
|
|
r_load_self r0
|
|
r_load_float r0, r0
|
|
n_dnan r1, r0
|
|
r_load_bool r0, r1
|
|
r_ret r0
|
|
|
|
# TODO: teach the bytecode compiler better
|
|
push_true
|
|
end
|
|
end
|
|
|
|
def infinite?
|
|
Rubinius.asm do
|
|
no = new_label
|
|
|
|
r0 = new_register
|
|
r1 = new_register
|
|
r2 = new_register
|
|
|
|
r_load_self r0
|
|
r_load_float r0, r0
|
|
n_dinf r1, r0
|
|
|
|
r_load_0 r0
|
|
n_ieq r2, r1, r0
|
|
b_if r2, no
|
|
|
|
r_store_int r0, r1
|
|
r_ret r0
|
|
|
|
no.set!
|
|
r_load_nil r0, 0
|
|
r_ret r0
|
|
|
|
# TODO: teach the bytecode compiler better
|
|
push_true
|
|
end
|
|
end
|
|
|
|
def finite?
|
|
not (nan? or infinite?)
|
|
end
|
|
|
|
def to_f
|
|
self
|
|
end
|
|
|
|
def to_i
|
|
Rubinius.primitive :float_to_i
|
|
raise PrimitiveFailure, "Float#to_i primitive failed"
|
|
end
|
|
|
|
alias_method :to_int, :to_i
|
|
alias_method :truncate, :to_i
|
|
|
|
def to_s
|
|
to_s_minimal
|
|
end
|
|
|
|
alias_method :inspect, :to_s
|
|
|
|
def to_s_minimal
|
|
Rubinius.primitive :float_to_s_minimal
|
|
raise PrimitiveFailure, "Float#to_s_minimal primitive failed: output exceeds buffer size"
|
|
end
|
|
|
|
def to_s_formatted(fmt)
|
|
Rubinius.primitive :float_to_s_formatted
|
|
raise PrimitiveFailure, "Float#to_s_formatted primitive failed: output exceeds buffer size"
|
|
end
|
|
private :to_s_formatted
|
|
|
|
def dtoa
|
|
Rubinius.primitive :float_dtoa
|
|
raise PrimitiveFailure, "Fload#dtoa primitive failed"
|
|
end
|
|
|
|
def to_packed(size)
|
|
Rubinius.primitive :float_to_packed
|
|
raise PrimitiveFailure, "Float#to_packed primitive failed"
|
|
end
|
|
|
|
def ceil
|
|
int = to_i()
|
|
|
|
return int if self == int or self < 0
|
|
return int + 1
|
|
end
|
|
|
|
def floor
|
|
int = to_i()
|
|
|
|
return int if self > 0 or self == int
|
|
return int - 1
|
|
end
|
|
|
|
def next_float
|
|
return NAN if self.nan?
|
|
return -MAX if self == -INFINITY
|
|
return INFINITY if self == MAX
|
|
return Math.ldexp(0.5, MIN_EXP - MANT_DIG + 1) if self.zero?
|
|
|
|
frac, exp = Math.frexp self
|
|
|
|
if frac == -0.5
|
|
frac *= 2
|
|
exp -= 1
|
|
end
|
|
|
|
smallest_frac = EPSILON / 2
|
|
smallest_frac = Math.ldexp(smallest_frac, MIN_EXP - exp) if exp < MIN_EXP
|
|
|
|
result_frac = frac + smallest_frac
|
|
|
|
return -0.0 if result_frac.zero? && frac < 0
|
|
return 0.0 if result_frac.zero? && frac > 0
|
|
|
|
return Math.ldexp result_frac, exp
|
|
end
|
|
|
|
def prev_float
|
|
return -(-self).next_float
|
|
end
|
|
end
|