Skip to content

Commit

Permalink
re-enable BigInt hexadecimal literals (#23546)
Browse files Browse the repository at this point in the history
  • Loading branch information
rfourquet committed Oct 11, 2020
1 parent 0c5329c commit d83d81e
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 24 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ New language features
product of two arrays of arrays. ([#37583])
* The syntax `import A as B` (plus `import A: x as y`, `import A.x as y`, and `using A: x as y`)
can now be used to rename imported modules and identifiers ([#1255]).
* Unsigned literals (starting with `0x`) which are too big to fit in an `UInt128` object
are now interpreted as `BigInt` ([#23546]).

Language changes
----------------
Expand Down
27 changes: 24 additions & 3 deletions doc/src/manual/integers-and-floating-point-numbers.md
Original file line number Diff line number Diff line change
Expand Up @@ -534,9 +534,18 @@ the [GNU Multiple Precision Arithmetic Library (GMP)](https://gmplib.org) and th
respectively. The [`BigInt`](@ref) and [`BigFloat`](@ref) types are available in Julia for arbitrary
precision integer and floating point numbers respectively.

Constructors exist to create these types from primitive numerical types, and the [string literal](@ref non-standard-string-literals) [`@big_str`](@ref) or [`parse`](@ref)
can be used to construct them from `AbstractString`s. Once created, they participate in arithmetic
with all other numeric types thanks to Julia's [type promotion and conversion mechanism](@ref conversion-and-promotion):
Constructors exist to create these types from primitive numerical types, and the
[string literal](@ref non-standard-string-literals) [`@big_str`](@ref) or [`parse`](@ref)
can be used to construct them from `AbstractString`s.
`BigInt`s can also be input as integer literals when
they are too big for other built-in integer types. Note that as there
is no unsigned arbitrary-precision integer type in `Base` (`BigInt` is
sufficient in most cases), hexadecimal, octal and binary literals can
be used (in addition to decimal literals).

Once created, they participate in arithmetic
with all other numeric types thanks to Julia's
[type promotion and conversion mechanism](@ref conversion-and-promotion):

```jldoctest
julia> BigInt(typemax(Int64)) + 1
Expand All @@ -548,6 +557,18 @@ julia> big"123456789012345678901234567890" + 1
julia> parse(BigInt, "123456789012345678901234567890") + 1
123456789012345678901234567891
julia> string(big"2"^200, base=16)
"100000000000000000000000000000000000000000000000000"
julia> 0x100000000000000000000000000000000-1 == typemax(UInt128)
true
julia> 0x000000000000000000000000000000000
0
julia> typeof(ans)
BigInt
julia> big"1.23456789012345678901"
1.234567890123456789010000000000000000000000000000000000000000000000000000000004
Expand Down
8 changes: 5 additions & 3 deletions doc/src/manual/noteworthy-differences.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,16 +271,18 @@ For users coming to Julia from R, these are some noteworthy differences:
a larger size type, such as `Int64` (if `Int` is `Int32`), `Int128`, or the arbitrarily large
`BigInt` type. There are no numeric literal suffixes, such as `L`, `LL`, `U`, `UL`, `ULL` to indicate
unsigned and/or signed vs. unsigned. Decimal literals are always signed, and hexadecimal literals
(which start with `0x` like C/C++), are unsigned. Hexadecimal literals also, unlike C/C++/Java
(which start with `0x` like C/C++), are unsigned, unless when they encode more than 128 bits,
in which case they are of type `BigInt`. Hexadecimal literals also, unlike C/C++/Java
and unlike decimal literals in Julia, have a type based on the *length* of the literal, including
leading 0s. For example, `0x0` and `0x00` have type [`UInt8`](@ref), `0x000` and `0x0000` have type
[`UInt16`](@ref), then literals with 5 to 8 hex digits have type `UInt32`, 9 to 16 hex digits type
`UInt64` and 17 to 32 hex digits type `UInt128`. This needs to be taken into account when defining
`UInt64`, 17 to 32 hex digits type `UInt128`, and more that 32 hex digits type `BigInt`.
This needs to be taken into account when defining
hexadecimal masks, for example `~0xf == 0xf0` is very different from `~0x000f == 0xfff0`. 64 bit `Float64`
and 32 bit [`Float32`](@ref) bit literals are expressed as `1.0` and `1.0f0` respectively. Floating point
literals are rounded (and not promoted to the `BigFloat` type) if they can not be exactly represented.
Floating point literals are closer in behavior to C/C++. Octal (prefixed with `0o`) and binary
(prefixed with `0b`) literals are also treated as unsigned.
(prefixed with `0b`) literals are also treated as unsigned (or `BigInt` for more than 128 bits).
* String literals can be delimited with either `"` or `"""`, `"""` delimited literals can contain
`"` characters without quoting it like `"\""`. String literals can have values of other variables
or expressions interpolated into them, indicated by `$variablename` or `$(expression)`, which
Expand Down
4 changes: 2 additions & 2 deletions src/julia-parser.scm
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@
((<= l 32) (numchk n s) (uint32 n))
((<= l 64) (numchk n s) (uint64 n))
((<= l 128) `(macrocall (core @uint128_str) (null) ,s))
(else (error "Hex or binary literal too large for UInt128")))))
(else `(macrocall (core @big_str) (null) ,s)))))

(define (sized-uint-oct-literal n s)
(if (string.find s "o0")
Expand All @@ -449,7 +449,7 @@
(begin (if (equal? s "0o") (numchk n s))
(if (oct-within-uint128? s)
`(macrocall (core @uint128_str) (null) ,s)
(error "Octal literal too large for UInt128"))))))
`(macrocall (core @big_str) (null) ,s))))))

(define (strip-leading-0s s)
(define (loop i)
Expand Down
29 changes: 13 additions & 16 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1691,8 +1691,7 @@ end
@test isa(0b0000000000000000000000000000000000000000000000000000000000000000,UInt64)
@test isa(0b00000000000000000000000000000000000000000000000000000000000000000,UInt128)
@test isa(0b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,UInt128)
# remove BigInt unsigned integer literals #11105
@test_throws Meta.ParseError Meta.parse("0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
@test isa(0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,BigInt)
@test isa(0b11111111,UInt8)
@test isa(0b111111111,UInt16)
@test isa(0b1111111111111111,UInt16)
Expand All @@ -1702,8 +1701,7 @@ end
@test isa(0b1111111111111111111111111111111111111111111111111111111111111111,UInt64)
@test isa(0b11111111111111111111111111111111111111111111111111111111111111111,UInt128)
@test isa(0b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111,UInt128)
# remove BigInt unsigned integer literals #11105
@test_throws Meta.ParseError Meta.parse("0b111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")
@test isa(0b111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111,BigInt)
end
@testset "octal literals" begin
@test 0o10 == 0x8
Expand All @@ -1719,8 +1717,7 @@ end
@test isa(0o000000000000000000000,UInt64)
@test isa(0o0000000000000000000000,UInt64)
@test isa(0o000000000000000000000000000000000000000000,UInt128)
# remove BigInt unsigned integer literals #11105
@test_throws Meta.ParseError Meta.parse("0o00000000000000000000000000000000000000000000")
@test isa(0o00000000000000000000000000000000000000000000,BigInt)
@test isa(0o11,UInt8)
@test isa(0o111,UInt8)
@test isa(0o11111,UInt16)
Expand All @@ -1732,9 +1729,8 @@ end
@test isa(0o111111111111111111111111111111111111111111,UInt128)
@test isa(0o1111111111111111111111111111111111111111111,UInt128)
@test isa(0o3777777777777777777777777777777777777777777,UInt128)
@test_throws Meta.ParseError Meta.parse("0o4000000000000000000000000000000000000000000")
# remove BigInt unsigned integer literals #11105
@test_throws Meta.ParseError Meta.parse("0o11111111111111111111111111111111111111111111")
@test isa(0o11111111111111111111111111111111111111111111,BigInt)
@test 0o4000000000000000000000000000000000000000000 == 340282366920938463463374607431768211456
@test isa(0o077, UInt8)
@test isa(0o377, UInt8)
@test isa(0o400, UInt16)
Expand All @@ -1750,7 +1746,6 @@ end
@test isa(0o0000000000000000000000000000000000000000000, UInt128)
@test isa(0o1000000000000000000000000000000000000000000, UInt128)
@test isa(0o2000000000000000000000000000000000000000000, UInt128)
@test_throws Meta.ParseError Meta.parse("0o4000000000000000000000000000000000000000000")

@test String([0o110, 0o145, 0o154, 0o154, 0o157, 0o054, 0o040, 0o127, 0o157, 0o162, 0o154, 0o144, 0o041]) == "Hello, World!"

Expand All @@ -1765,8 +1760,7 @@ end
@test isa(0x0000000000000000,UInt64)
@test isa(0x00000000000000000,UInt128)
@test isa(0x00000000000000000000000000000000,UInt128)
# remove BigInt unsigned integer literals #11105
@test_throws Meta.ParseError Meta.parse("0x000000000000000000000000000000000")
@test isa(0x000000000000000000000000000000000,BigInt)

@test isa(0x11,UInt8)
@test isa(0x111,UInt16)
Expand All @@ -1777,8 +1771,7 @@ end
@test isa(0x1111111111111111,UInt64)
@test isa(0x11111111111111111,UInt128)
@test isa(0x11111111111111111111111111111111,UInt128)
# remove BigInt unsigned integer literals #11105
@test_throws Meta.ParseError Meta.parse("0x111111111111111111111111111111111")
@test isa(0x111111111111111111111111111111111,BigInt)
end
@testset "minus sign and unsigned literals" begin
# "-" is not part of unsigned literals
Expand All @@ -1792,13 +1785,17 @@ end
@test -0o0000000000000000000001 == -(0o0000000000000000000001)
@test -0b00000000000000000000000000000000000000000000000000000000000000001 ==
-(0b00000000000000000000000000000000000000000000000000000000000000001)
@test -0x000000000000000000000000000000001 == -(0x000000000000000000000000000000001)
@test -0o0000000000000000000000000000000000000000001 ==
-(0o0000000000000000000000000000000000000000001)
@test -0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ==
-(0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001)

@test isa(-0x00,UInt8)
@test isa(-0x0000000000000000,UInt64)
@test isa(-0x00000000000000000,UInt128)
@test isa(-0x00000000000000000000000000000000,UInt128)
# remove BigInt unsigned integer literals #11105
@test_throws Meta.ParseError Meta.parse("-0x000000000000000000000000000000000")
@test isa(-0x000000000000000000000000000000000,BigInt)
end
@testset "Float32 literals" begin
@test isa(1f0,Float32)
Expand Down

0 comments on commit d83d81e

Please sign in to comment.