0.1 > 1//10
true
Each finite floating point number corresponds to a single real number
@printf "%.60f" 0.1
0.100000000000000005551115123125782702118158340454101562500000
promote
?¶Most languages do!
≃(x::Real,y::Real) = ≃(promote(x,y)...)
≃(x::T, y::T) where {T<:Real} = x == y
≃ (generic function with 2 methods)
0.1 ≃ 1//10 ≃ 0.1f0
true
1//10 ≃ 0.1 ≃ 0.1f0
false
≃
is not a transitive relation:
0.1 ≃ 1//10
true
1//10 ≃ 0.1f0
true
0.1 ≃ 0.1f0
false
We can do better.
UInt32 | UInt64 | Int32 | Int64 | BigInt | Float32 | Float64 | BigFloat | Rational | Irrational | |
---|---|---|---|---|---|---|---|---|---|---|
UInt32 | ||||||||||
UInt64 | ||||||||||
Int32 | ||||||||||
Int64 | ||||||||||
BigInt | ||||||||||
Float32 | ||||||||||
Float64 | ||||||||||
BigFloat | ||||||||||
Rational | ||||||||||
Irrational |
sum(1:10)
55
These are defined by LLVM, and typically reduce to native CPU instruction.
<(x::Float64, y::Float64) = lt_float(x, y)
@code_llvm 1.0 < 1.0
define i8 @"jlsys_<_60112"(double, double) #0 !dbg !5 { top: %2 = fcmp olt double %0, %1 %3 = zext i1 %2 to i8 ret i8 %3 }
@code_native 1.0 < 1.0
.section __TEXT,__text,regular,pure_instructions Filename: float.jl pushl %ebp decl %eax movl %esp, %ebp Source line: 432 ucomisd %xmm0, %xmm1 seta %al popl %ebp retl Source line: 432 nop nop nop
UInt32 | UInt64 | Int32 | Int64 | BigInt | Float32 | Float64 | BigFloat | Rational | Irrational | |
---|---|---|---|---|---|---|---|---|---|---|
UInt32 | ||||||||||
UInt64 | ||||||||||
Int32 | ||||||||||
Int64 | ||||||||||
BigInt | ||||||||||
Float32 | ||||||||||
Float64 | ||||||||||
BigFloat | ||||||||||
Rational | ||||||||||
Irrational |
Certain conversions can be done exactly (without changing the underlying numeric value):
UInt32
$\rightarrow$ UInt64
Int32
$\rightarrow$ Int64
UInt32
$\rightarrow$ Float64
Int32
$\rightarrow$ Float64
Float32
$\rightarrow$ Float64
We can use this to fill in some gaps.
UInt32 | UInt64 | Int32 | Int64 | BigInt | Float32 | Float64 | BigFloat | Rational | Irrational | |
---|---|---|---|---|---|---|---|---|---|---|
UInt32 | ||||||||||
UInt64 | ||||||||||
Int32 | ||||||||||
Int64 | ||||||||||
BigInt | ||||||||||
Float32 | ||||||||||
Float64 | ||||||||||
BigFloat | ||||||||||
Rational | ||||||||||
Irrational |
BigInt
and BigFloat
are wrappers around external libraries (GMP and MPFR), which provide various comparison operators.
UInt32 | UInt64 | Int32 | Int64 | BigInt | Float32 | Float64 | BigFloat | Rational | Irrational | |
---|---|---|---|---|---|---|---|---|---|---|
UInt32 | ||||||||||
UInt64 | ||||||||||
Int32 | ||||||||||
Int64 | ||||||||||
BigInt | ||||||||||
Float32 | ||||||||||
Float64 | ||||||||||
BigFloat | ||||||||||
Rational | ||||||||||
Irrational |
<( x::BitSigned, y::BitUnsigned) = (x < 0) | (unsigned(x) < y)
<( x::BitUnsigned, y::BitSigned ) = (y >= 0) & (x < unsigned(y))
unsigned
simply reinterprets a signed as an unsigned integer
UInt32 | UInt64 | Int32 | Int64 | BigInt | Float32 | Float64 | BigFloat | Rational | Irrational | |
---|---|---|---|---|---|---|---|---|---|---|
UInt32 | ||||||||||
UInt64 | ||||||||||
Int32 | ||||||||||
Int64 | ||||||||||
BigInt | ||||||||||
Float32 | ||||||||||
Float64 | ||||||||||
BigFloat | ||||||||||
Rational | ||||||||||
Irrational |
Int64
/UInt64
vs Float64
¶function <(x::Float64, y::Union{UInt64, Int64})
fy = Float64(y)
(x < fy) | ((x == fy) & (fy < Float64(typemax(y))) & (unsafe_trunc(typeof(y),fy) < y))
end
Float64
!=
, then we're done!
==
, there may have been rounding in step 1.
2.0^64
/ 2.0^63
61fe3b9c3
was the initial commit).
UInt32 | UInt64 | Int32 | Int64 | BigInt | Float32 | Float64 | BigFloat | Rational | Irrational | |
---|---|---|---|---|---|---|---|---|---|---|
UInt32 | ||||||||||
UInt64 | ||||||||||
Int32 | ||||||||||
Int64 | ||||||||||
BigInt | ||||||||||
Float32 | ||||||||||
Float64 | ||||||||||
BigFloat | ||||||||||
Rational | ||||||||||
Irrational |
Rational
vs Integer
/Rational
¶Cross-multiply the denominator:
<(x::Rational, y::Integer ) = x.num < widemul(x.den,y)
<(x::Rational, y::Rational) = widemul(x.num,y.den) < widemul(x.den,y.num)
widemul
returns an integer of a sufficiently wide type so that there is no overflow
UInt32 | UInt64 | Int32 | Int64 | BigInt | Float32 | Float64 | BigFloat | Rational | Irrational | |
---|---|---|---|---|---|---|---|---|---|---|
UInt32 | ||||||||||
UInt64 | ||||||||||
Int32 | ||||||||||
Int64 | ||||||||||
BigInt | ||||||||||
Float32 | ||||||||||
Float64 | ||||||||||
BigFloat | ||||||||||
Rational | ||||||||||
Irrational |
Rational
vs floating point¶function <(x::Rational, y::AbstractFloat)
(isnan(x) || isnan(y)) && return false
xn, xp, xd = decompose(x)
yn, yp, yd = decompose(y)
if xd < 0
xn = -xn
xd = -xd
end
if yd < 0
yn = -yn
yd = -yd
end
xc, yc = widemul(xn,yd), widemul(yn,xd)
xs, ys = sign(xc), sign(yc)
if xs != ys
return xs < ys
elseif xs == 0
# both are zero or ±Inf
return xn < yn
end
xb, yb = ndigits0z(xc,2) + xp, ndigits0z(yc,2) + yp
if xb == yb
xc, yc = promote(xc,yc)
if xp > yp
xc = (xc<<(xp-yp))
else
yc = (yc<<(yp-xp))
end
return xc < yc
else
return xc > 0 ? xb < yb : yb < xb
end
end
UInt32 | UInt64 | Int32 | Int64 | BigInt | Float32 | Float64 | BigFloat | Rational | Irrational | |
---|---|---|---|---|---|---|---|---|---|---|
UInt32 | ||||||||||
UInt64 | ||||||||||
Int32 | ||||||||||
Int64 | ||||||||||
BigInt | ||||||||||
Float32 | ||||||||||
Float64 | ||||||||||
BigFloat | ||||||||||
Rational | ||||||||||
Irrational |
Irrational
s¶Julia provides various constants as a parametric type
pi
π = 3.1415926535897...
Float64(pi) < pi
true
typeof(pi)
Irrational{:π}
Irrational
vs Float64
¶<(x::Irrational, y::Float64) = Float64(x,RoundUp) <= y
<(x::Float64, y::Irrational) = x <= Float64(y,RoundDown)
Irrational
must occur between two Float64
s (since a Float64
is always rational).
Float64(x, RoundUp)
gives the smallest Float64
which is greater than or equal to x
.
UInt32 | UInt64 | Int32 | Int64 | BigInt | Float32 | Float64 | BigFloat | Rational | Irrational | |
---|---|---|---|---|---|---|---|---|---|---|
UInt32 | ||||||||||
UInt64 | ||||||||||
Int32 | ||||||||||
Int64 | ||||||||||
BigInt | ||||||||||
Float32 | ||||||||||
Float64 | ||||||||||
BigFloat | ||||||||||
Rational | ||||||||||
Irrational |
Irrational
vs BigFloat
¶<(x::Irrational, y::BigFloat) = setprecision(precision(y)+32) do
big(x) < y
end
UInt32 | UInt64 | Int32 | Int64 | BigInt | Float32 | Float64 | BigFloat | Rational | Irrational | |
---|---|---|---|---|---|---|---|---|---|---|
UInt32 | ||||||||||
UInt64 | ||||||||||
Int32 | ||||||||||
Int64 | ||||||||||
BigInt | ||||||||||
Float32 | ||||||||||
Float64 | ||||||||||
BigFloat | ||||||||||
Rational | ||||||||||
Irrational |
Irrational
vs Rational
¶function <(x::AbstractIrrational, y::Rational{T}) where T
T <: Unsigned && x < 0.0 && return true
rx = rationalize(T, x)
if lessrational(rx, x)
return rx < y
else
return rx <= y
end
end
rational(T, x::Irrational)
gives the closest rational number to x
that fits whose coefficients fit within type T
x
).
lessrational(rx,x)
is an @pure
version of rx < big(x)
Can't be used for Rational{BigInt}
Irrational
vs Rational{BigInt}
¶<(x::AbstractIrrational, y::Rational{BigInt}) = big(x) < y
Not strictly correct:
r = 45471447111470790535029367847216232831674172166049053744846518889742361808273//
14474011154664524427946373126085988481658748083205070504932198000989141204992
45471447111470790535029367847216232831674172166049053744846518889742361808273//14474011154664524427946373126085988481658748083205070504932198000989141204992
r < pi
false
setprecision(BigFloat, 1024) do
r < pi
end
true
Use the fact that the convergents alternate between being smaller and larger: work your way down the continued fraction until you can say for sure.
UInt32 | UInt64 | Int32 | Int64 | BigInt | Float32 | Float64 | BigFloat | Rational | Irrational | |
---|---|---|---|---|---|---|---|---|---|---|
UInt32 | ||||||||||
UInt64 | ||||||||||
Int32 | ||||||||||
Int64 | ||||||||||
BigInt | ||||||||||
Float32 | ||||||||||
Float64 | ||||||||||
BigFloat | ||||||||||
Rational | ||||||||||
Irrational |
Irrational
vs Irrational
¶# julia 0.6
pi < pi
< not defined for Irrational{:π} Stacktrace: [1] <(::Irrational{:π}, ::Irrational{:π}) at ./promotion.jl:350
Per Rutquist fixed this a month ago for 0.7/1.0 (#27797):
<(::Irrational{s}, ::Irrational{s}) where {s} = false
function <(x::AbstractIrrational, y::AbstractIrrational)
Float64(x) != Float64(y) || throw(MethodError(<, (x, y)))
return Float64(x) < Float64(y)
end
UInt32 | UInt64 | Int32 | Int64 | BigInt | Float32 | Float64 | BigFloat | Rational | Irrational | |
---|---|---|---|---|---|---|---|---|---|---|
UInt32 | ||||||||||
UInt64 | ||||||||||
Int32 | ||||||||||
Int64 | ||||||||||
BigInt | ||||||||||
Float32 | ||||||||||
Float64 | ||||||||||
BigFloat | ||||||||||
Rational | ||||||||||
Irrational |
using DecFP
d64"1e100" == 1e100
true
BigInt(1e100)
10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104