Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integers in the type domain #55571

Closed
wants to merge 64 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
a36791a
import from src/ from my package TypeDomainNaturalNumbers.jl
nsajko Aug 19, 2024
da72b8b
rename module `TypeDomainNaturalNumbers` to `TypeDomainIntegers`
nsajko Aug 19, 2024
22991b8
add copyright notice
nsajko Aug 19, 2024
48ed9e5
include the new file into `Base`
nsajko Aug 19, 2024
e71bf9b
make the new types subtype `Integer`
nsajko Aug 19, 2024
2bf4b17
delete `NegativeInteger` constructor to prevent ambiguity
nsajko Aug 21, 2024
3b93756
delete `with_refined_type`, just use the type assertion directly
nsajko Aug 19, 2024
ee728a5
don't add ambiguous methods to `Base`
nsajko Aug 19, 2024
97c0d82
refactor: introduce `interoperable`
nsajko Aug 19, 2024
3f5a1a7
base the interoperability with other numbers on `Int8`
nsajko Aug 19, 2024
59af5d8
support conversion from/to other primitive types
nsajko Aug 19, 2024
81b9621
`interoperable`: return `Bool` when possible
nsajko Aug 19, 2024
e7b09c5
import the tests from my Gitlab, adjust
nsajko Aug 19, 2024
e4ba24f
fix dispatch to conversion to `Bool`
nsajko Aug 20, 2024
a05a7ec
export the `apply_` functions from `BaseHelpers`
nsajko Aug 20, 2024
302fa38
delete `apply_` fallbacks
nsajko Aug 20, 2024
33db6a5
implement `apply_` for equality
nsajko Aug 20, 2024
d216418
implement promotion
nsajko Aug 20, 2024
728e59e
instead of forcing a narrow type, widen on overflow
nsajko Aug 21, 2024
15698f4
`BaseHelpers`: simplify, `tdi_to_int` now may return `Bool`
nsajko Aug 21, 2024
d3f8933
`BaseHelpers`: `interoperable` -> `tdi_to_int`
nsajko Aug 21, 2024
a0b0c9a
`BaseHelpers`: bugfix for equality: import `iszero`
nsajko Aug 23, 2024
3c29e5b
`BaseHelpers`: `a - b` -> `a + -b`
nsajko Aug 21, 2024
ade3b06
define binary operations using `BaseHelpers`
nsajko Aug 23, 2024
6f463f4
implement `abs`
nsajko Aug 21, 2024
8a3b13f
implement promotion between `TypeDomainInteger` subtypes
nsajko Aug 21, 2024
f213c52
implement conversion to `AbstractFloat`
nsajko Aug 22, 2024
9fcf4a2
delete `tdnn_to_x`, it's unused
nsajko Aug 22, 2024
6858b76
implement `tdnn_from_int(::Bool)`, `tdi_from_int(::Bool)`
nsajko Aug 22, 2024
49809ff
implement `<:AbstractFloat` constructors taking `RoundingMode`
nsajko Aug 22, 2024
8799b83
implement `signbit`
nsajko Aug 22, 2024
7dd4350
implement `sign`
nsajko Aug 22, 2024
47b6abc
specialize `inv`
nsajko Aug 23, 2024
9835209
implement `widen`
nsajko Aug 23, 2024
de6b57b
specialize `show`
nsajko Aug 23, 2024
58dd019
use `TypeDomainIntegers` from `Base`
nsajko Aug 22, 2024
730a5aa
implement `isqrt`
nsajko Aug 22, 2024
af5bc27
implement `factorial`
nsajko Aug 22, 2024
29a3435
`to_power_type(@nospecialize x::TypeDomainInteger) = x`
nsajko Aug 22, 2024
0a99dc0
use `TypeDomainIntegers` from `Base.Math`
nsajko Aug 22, 2024
6545620
math: implement `sqrt` `cbrt`, `fourthroot`
nsajko Aug 22, 2024
8c1920a
math: `hypot(x::TypeDomainInteger) = abs(x)`
nsajko Aug 22, 2024
de04594
math: specialize `deg2rad`, `rad2deg`
nsajko Aug 22, 2024
b2e9757
math: specialize logarithms
nsajko Aug 22, 2024
5670b8d
math: specialize `exp2`, `exp10`, `expm1`
nsajko Aug 22, 2024
c4f0c51
math: specialize some hyperbolic functions
nsajko Aug 22, 2024
1bceeb6
math: specialize `sind`, `asind`, `cosd`, `acosd`, `secd`, `asecd`
nsajko Aug 22, 2024
59bff74
math: specialize `sinpi`, `cospi`, `tanpi`
nsajko Aug 22, 2024
95d9cea
math: specialize `sinc`, `cosc`
nsajko Aug 23, 2024
301b575
complex: specialize `imag(::Real)`
nsajko Aug 22, 2024
21dd6b9
complex: specialize `cispi`
nsajko Aug 23, 2024
8d02b19
rational: make `denominator(::Integer)` return type domain one
nsajko Aug 23, 2024
b8abb9e
gmp: conversion from `BigInt`
nsajko Aug 22, 2024
4ab3521
mpfr: conversion from `BigFloat`
nsajko Aug 22, 2024
51c2863
irrationals: `zero`, `one`, `sign`
nsajko Aug 22, 2024
fb97552
`MathConstants`: return type domain integers when that makes sense
nsajko Aug 22, 2024
1a62a82
specialize: angle exp sin tan cos asin atan acos
nsajko Aug 22, 2024
c6b1a50
gmp, mpfr, irrationals: define binary operations using `BaseHelpers`
nsajko Aug 23, 2024
8f16391
update tests: relax `===` to `==`
nsajko Aug 23, 2024
7de1320
test issue #37977
nsajko Aug 23, 2024
8900ea3
complex: nospecialize for `cispi`
nsajko Aug 23, 2024
2116f13
InteractiveUtils: fix/disable doc test
nsajko Aug 23, 2024
eaa25f9
uncomment some tests
nsajko Aug 23, 2024
55c423b
delete redundant `isequal` and `==` methods
nsajko Aug 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ end
# numeric operations
include("hashing.jl")
include("rounding.jl")
include("typedomainintegers.jl"); using .TypeDomainIntegers
include("div.jl")
include("rawbigints.jl")
include("float.jl")
Expand Down Expand Up @@ -521,6 +522,8 @@ include("irrationals.jl")
include("mathconstants.jl")
using .MathConstants: ℯ, π, pi

include("typedomainintegers_irrationals.jl")

# Stack frames and traces
include("stacktraces.jl")
using .StackTraces
Expand Down
10 changes: 9 additions & 1 deletion base/complex.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ julia> imag(1 + 3im)
"""
imag(z::Complex) = z.im
real(x::Real) = x
imag(x::Real) = zero(x)
imag(@nospecialize x::Real) = zero(NonnegativeInteger)

"""
reim(z)
Expand Down Expand Up @@ -613,6 +613,14 @@ julia> cispi(0.25 + 1im)
"""
function cispi end
cispi(theta::Real) = Complex(reverse(sincospi(theta))...)
function cispi(@nospecialize n::TypeDomainInteger)
o = one(TypeDomainInteger)
if iseven(n)
o
else
-o
end
end

function cispi(z::Complex)
v = exp(-(pi*imag(z)))
Expand Down
25 changes: 25 additions & 0 deletions base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import .Base: *, +, -, /, <, <<, >>, >>>, <=, ==, >, >=, ^, (~), (&), (|), xor,
sign, hastypemax, isodd, iseven, digits!, hash, hash_integer, top_set_bit,
clamp

using ..TypeDomainIntegers

if Clong == Int32
const ClongMax = Union{Int8, Int16, Int32}
const CulongMax = Union{UInt8, UInt16, UInt32}
Expand Down Expand Up @@ -389,6 +391,18 @@ function (::Type{T})(x::BigInt) where T<:Base.BitSigned
end
end

function convert(::Type{NonnegativeInteger}, x::BigInt)
TypeDomainIntegers.Conversion.tdnn_from_x(x)
end
function convert(::Type{TypeDomainInteger}, x::BigInt)
TypeDomainIntegers.Conversion.tdi_from_x(x)
end
function NonnegativeInteger(x::BigInt)
TypeDomainIntegers.Conversion.tdnn_from_x(x)
end
function TypeDomainInteger(x::BigInt)
TypeDomainIntegers.Conversion.tdi_from_x(x)
end

Float64(n::BigInt, ::RoundingMode{:ToZero}) = MPZ.get_d(n)

Expand Down Expand Up @@ -566,6 +580,17 @@ end
/(x::BigInt, y::Union{ClongMax,CulongMax}) = float(x)/y
/(x::Union{ClongMax,CulongMax}, y::BigInt) = x/float(y)

for func ∈ (:+, :-, :*, :(==))
@eval begin
function Base.$func((@nospecialize l::BigInt), (@nospecialize r::TypeDomainInteger))
TypeDomainIntegers.BaseHelpers.apply_n_t($func, l, r)
end
function Base.$func((@nospecialize l::TypeDomainInteger), (@nospecialize r::BigInt))
TypeDomainIntegers.BaseHelpers.apply_t_n($func, l, r)
end
end
end

# unary ops
(-)(x::BigInt) = MPZ.neg(x)
(~)(x::BigInt) = MPZ.com(x)
Expand Down
28 changes: 28 additions & 0 deletions base/intfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ end

# ^ for any x supporting *
to_power_type(x) = convert(Base._return_type(*, Tuple{typeof(x), typeof(x)}), x)
to_power_type(@nospecialize x::TypeDomainInteger) = x
@noinline throw_domerr_powbysq(::Any, p) = throw(DomainError(p, LazyString(
"Cannot raise an integer x to a negative power ", p, ".",
"\nConvert input to float.")))
Expand Down Expand Up @@ -1110,6 +1111,20 @@ function isqrt(x::Union{Int64,UInt64,Int128,UInt128})
s*s > x ? s-1 : s
end

function isqrt(@nospecialize n::Union{
typeof(NonnegativeInteger(0)),
typeof(NonnegativeInteger(1)),
typeof(NonnegativeInteger(2)),
typeof(NonnegativeInteger(3)),
})
z = zero(NonnegativeInteger)
if n isa PositiveIntegerUpperBound
natural_successor(z)
else
z
end
end

"""
factorial(n::Integer)

Expand Down Expand Up @@ -1145,6 +1160,19 @@ function factorial(n::Integer)
return f
end

function factorial(@nospecialize n::Union{
typeof(NonnegativeInteger(0)),
typeof(NonnegativeInteger(1)),
typeof(NonnegativeInteger(2)),
})
two = NonnegativeInteger(2)
if n === two
two
else
one(NonnegativeInteger)
end
end

"""
binomial(n::Integer, k::Integer)

Expand Down
28 changes: 23 additions & 5 deletions base/irrationals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ end
<=(x::AbstractIrrational, y::AbstractFloat) = x < y
<=(x::AbstractFloat, y::AbstractIrrational) = x < y

for func ∈ (:+, :-, :*, :(==))
@eval begin
function Base.$func((@nospecialize l::Irrational), (@nospecialize r::TypeDomainInteger))
TypeDomainIntegers.BaseHelpers.apply_n_t($func, l, r)
end
function Base.$func((@nospecialize l::TypeDomainInteger), (@nospecialize r::Irrational))
TypeDomainIntegers.BaseHelpers.apply_t_n($func, l, r)
end
end
end

# Irrational vs Rational
@assume_effects :total function rationalize(::Type{T}, x::AbstractIrrational; tol::Real=0) where T
return rationalize(T, big(x), tol=tol)
Expand Down Expand Up @@ -151,13 +162,20 @@ hash(x::Irrational, h::UInt) = 3*objectid(x) - h

widen(::Type{T}) where {T<:Irrational} = T

zero(::AbstractIrrational) = false
zero(::Type{<:AbstractIrrational}) = false
zero(::AbstractIrrational) = zero(TypeDomainInteger)
zero(::Type{<:AbstractIrrational}) = zero(TypeDomainInteger)

one(::AbstractIrrational) = true
one(::Type{<:AbstractIrrational}) = true
one(::AbstractIrrational) = one(TypeDomainInteger)
one(::Type{<:AbstractIrrational}) = one(TypeDomainInteger)

sign(x::AbstractIrrational) = ifelse(x < zero(x), -1.0, 1.0)
function sign(x::AbstractIrrational)
o = one(TypeDomainInteger)
if signbit(x)
-o
else
o
end
end

-(x::AbstractIrrational) = -Float64(x)
for op in Symbol[:+, :-, :*, :/, :^]
Expand Down
91 changes: 91 additions & 0 deletions base/math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ using Core.Intrinsics: sqrt_llvm

using .Base: IEEEFloat

using ..TypeDomainIntegers

@noinline function throw_complex_domainerror(f::Symbol, x)
throw(DomainError(x,
LazyString(f," was called with a negative real argument but will only return a complex result if called with a complex argument. Try ", f,"(Complex(x)).")))
Expand Down Expand Up @@ -262,6 +264,13 @@ deg2rad(z::Real) = deg2rad(float(z))
rad2deg(z::Number) = (z/pi)*180
deg2rad(z::Number) = (z*pi)/180

function deg2rad(@nospecialize z::typeof(zero(TypeDomainInteger)))
z
end
function rad2deg(@nospecialize z::typeof(zero(TypeDomainInteger)))
z
end

log(b::T, x::T) where {T<:Number} = log(x)/log(b)

"""
Expand Down Expand Up @@ -679,6 +688,16 @@ Return the fourth root of `x` by applying `sqrt` twice successively.
"""
fourthroot(x::Number) = sqrt(sqrt(x))

function sqrt(@nospecialize n::Union{typeof(NonnegativeInteger(0)),typeof(NonnegativeInteger(1))})
n
end
function cbrt(@nospecialize n::Union{typeof(NonnegativeInteger(0)),typeof(NonnegativeInteger(1))})
n
end
function fourthroot(@nospecialize n::Union{typeof(NonnegativeInteger(0)),typeof(NonnegativeInteger(1))})
n
end

"""
hypot(x, y)

Expand Down Expand Up @@ -823,6 +842,8 @@ function _hypot(x::NTuple{N,<:IEEEFloat}) where {N}
return scale * sqrt(mapreduce(y -> abs2(y * invscale), add_fast, x))
end

hypot(x::TypeDomainInteger) = abs(x)

atan(y::Real, x::Real) = atan(promote(float(y),float(x))...)
atan(y::T, x::T) where {T<:AbstractFloat} = Base.no_op_err("atan", T)

Expand Down Expand Up @@ -1594,4 +1615,74 @@ exp2(x::AbstractFloat) = 2^x
exp10(x::AbstractFloat) = 10^x
fourthroot(::Missing) = missing

function exp2(@nospecialize n::Union{
typeof(NonnegativeInteger(0)),
typeof(NonnegativeInteger(1)),
})
natural_successor(n)
end
function exp10(n::typeof(NonnegativeInteger(0)))
natural_successor(n)
end
function expm1(n::typeof(NonnegativeInteger(0)))
n
end

function sinh(n::typeof(NonnegativeInteger(0)))
n
end
function cosh(n::typeof(NonnegativeInteger(0)))
natural_successor(n)
end
function tanh(n::typeof(NonnegativeInteger(0)))
n
end
function sech(n::typeof(NonnegativeInteger(0)))
natural_successor(n)
end
function asinh(n::typeof(NonnegativeInteger(0)))
n
end
function acosh(n::typeof(NonnegativeInteger(1)))
natural_predecessor(n)
end
function atanh(n::typeof(NonnegativeInteger(0)))
n
end
function asech(n::typeof(NonnegativeInteger(1)))
natural_predecessor(n)
end

function log2(@nospecialize n::Union{typeof(NonnegativeInteger(1)),typeof(NonnegativeInteger(2))})
natural_predecessor(n)
end
function log10(@nospecialize n::typeof(NonnegativeInteger(1)))
zero(NonnegativeInteger)
end
function log(@nospecialize n::typeof(NonnegativeInteger(1)))
zero(NonnegativeInteger)
end
function log1p(@nospecialize n::typeof(NonnegativeInteger(0)))
zero(NonnegativeInteger)
end

function sind(n::typeof(NonnegativeInteger(0)))
n
end
function asind(n::typeof(NonnegativeInteger(0)))
n
end
function cosd(n::typeof(NonnegativeInteger(0)))
natural_successor(n)
end
function acosd(n::typeof(NonnegativeInteger(1)))
natural_predecessor(n)
end
function secd(n::typeof(NonnegativeInteger(0)))
natural_successor(n)
end
function asecd(n::typeof(NonnegativeInteger(1)))
natural_predecessor(n)
end

end # module
12 changes: 7 additions & 5 deletions base/mathconstants.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ See [`π`](@ref), [`ℯ`](@ref), [`γ`](@ref), [`φ`](@ref) and [`catalan`](@ref
"""
module MathConstants

using ..TypeDomainIntegers

export π, pi, ℯ, e, γ, eulergamma, catalan, φ, golden

Base.@irrational π pi
Expand Down Expand Up @@ -120,13 +122,13 @@ for T in (AbstractIrrational, Rational, Integer, Number, Complex)
end
Base.literal_pow(::typeof(^), ::Irrational{:ℯ}, ::Val{p}) where {p} = exp(p)

Base.log(::Irrational{:ℯ}) = 1 # use 1 to correctly promote expressions like log(x)/log(ℯ)
Base.log(::Irrational{:ℯ}) = one(TypeDomainInteger)
Base.log(::Irrational{:ℯ}, x::Number) = log(x)

Base.sin(::Irrational{:π}) = 0.0
Base.cos(::Irrational{:π}) = -1.0
Base.sincos(::Irrational{:π}) = (0.0, -1.0)
Base.tan(::Irrational{:π}) = 0.0
Base.sin(::Irrational{:π}) = zero(TypeDomainInteger)
Base.cos(::Irrational{:π}) = -one(TypeDomainInteger)
Base.sincos(::Irrational{:π}) = (zero(TypeDomainInteger), -one(TypeDomainInteger))
Base.tan(::Irrational{:π}) = zero(TypeDomainInteger)
Base.cot(::Irrational{:π}) = -1/0

end # module
29 changes: 28 additions & 1 deletion base/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import
RawBigIntRoundingIncrementHelper, truncated, RawBigInt


using .Base.Libc
using .Base.Libc, ..TypeDomainIntegers
import ..Rounding:
rounding_raw, setrounding_raw, rounds_to_nearest, rounds_away_from_zero,
tie_breaker_is_to_even, correct_rounding_requires_increment
Expand Down Expand Up @@ -402,6 +402,22 @@ function Bool(x::BigFloat)
isone(x) && return true
throw(InexactError(:Bool, Bool, x))
end
function convert(::Type{NonnegativeInteger}, x::BigFloat)
isinteger(x) || throw(InexactError(:NonnegativeInteger, NonnegativeInteger, x))
TypeDomainIntegers.Conversion.tdnn_from_x(x)
end
function convert(::Type{TypeDomainInteger}, x::BigFloat)
isinteger(x) || throw(InexactError(:TypeDomainInteger, TypeDomainInteger, x))
TypeDomainIntegers.Conversion.tdi_from_x(x)
end
function NonnegativeInteger(x::BigFloat)
isinteger(x) || throw(InexactError(:NonnegativeInteger, NonnegativeInteger, x))
TypeDomainIntegers.Conversion.tdnn_from_x(x)
end
function TypeDomainInteger(x::BigFloat)
isinteger(x) || throw(InexactError(:TypeDomainInteger, TypeDomainInteger, x))
TypeDomainIntegers.Conversion.tdi_from_x(x)
end
function BigInt(x::BigFloat)
isinteger(x) || throw(InexactError(:BigInt, BigInt, x))
trunc(BigInt, x)
Expand Down Expand Up @@ -951,6 +967,17 @@ cmp(x::CdoubleMax, y::BigFloat) = -cmp(y,x)
<=(x::BigFloat, y::CdoubleMax) = !isnan(x) && !isnan(y) && cmp(x,y) <= 0
<=(x::CdoubleMax, y::BigFloat) = !isnan(x) && !isnan(y) && cmp(y,x) >= 0

for func ∈ (:+, :-, :*, :(==))
@eval begin
function Base.$func((@nospecialize l::BigFloat), (@nospecialize r::TypeDomainInteger))
TypeDomainIntegers.BaseHelpers.apply_n_t($func, l, r)
end
function Base.$func((@nospecialize l::TypeDomainInteger), (@nospecialize r::BigFloat))
TypeDomainIntegers.BaseHelpers.apply_t_n($func, l, r)
end
end
end

# Note: this inlines the implementation of `mpfr_signbit` to avoid a
# `ccall`.
signbit(x::BigFloat) = signbit(x.sign)
Expand Down
2 changes: 1 addition & 1 deletion base/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ julia> denominator(4)
1
```
"""
denominator(x::Integer) = one(x)
denominator(@nospecialize x::Integer) = one(TypeDomainInteger)
denominator(x::Rational) = x.den

sign(x::Rational) = oftype(x, sign(x.num))
Expand Down
Loading