-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
253 additions
and
148 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
function Base.tryparse(::Type{Decimal}, str::AbstractString) | ||
regex = Regex(string( | ||
"^", | ||
# Optional sign | ||
"(?<sign>[+-])?", | ||
# Decimal part: either 1[234].[567] or [.]1[234] | ||
"(?<dec>(?:\\d+\\.\\d*)|(?:\\.?\\d+))", | ||
# Optional exponent part: e or E followed by optional sign and digits | ||
"(?<exp>[eE][+-]?\\d+)?", | ||
"\$" | ||
)) | ||
|
||
m = match(regex, str) | ||
if isnothing(m) | ||
return nothing | ||
end | ||
|
||
sign = m[:sign] | ||
deci_part = m[:dec] | ||
expo_part = m[:exp] | ||
|
||
# expo_part[1] is 'e' or 'E' | ||
exponent = isnothing(expo_part) ? 0 : parse(Int, @view expo_part[2:end]) | ||
|
||
int_frac = split(deci_part, ".", keepempty=true) | ||
if length(int_frac) == 1 | ||
# There is no decimal point | ||
coef = parse(BigInt, deci_part) | ||
elseif length(int_frac) == 2 | ||
# There is a decimal point | ||
int, frac = int_frac | ||
coef = parse(BigInt, int * frac) | ||
exponent -= length(frac) | ||
else | ||
@assert false # should never happen | ||
end | ||
|
||
negative = sign == "-" | ||
|
||
return Decimal(negative, coef, exponent) | ||
end | ||
|
||
function Base.parse(::Type{Decimal}, str::AbstractString) | ||
x = tryparse(Decimal, str) | ||
isnothing(x) && throw(ArgumentError("Invalid decimal: $str")) | ||
return x | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Show x without using exponential notation | ||
function show_plain(io::IO, x::Decimal) | ||
if x.s | ||
print(io, '-') | ||
end | ||
|
||
if x.q ≥ 0 | ||
# Print coefficient and `x.q` zeros | ||
print(io, x.c, repeat('0', x.q)) | ||
else # x.q < 0 | ||
coef = string(x.c) | ||
coefdigits = ncodeunits(coef) | ||
pointpos = -x.q # How many digits should go after the decimal point | ||
|
||
# If there are some (non-zero) digits before the decimal point, | ||
# print them, then print the decimal point, and then the digits after | ||
# the decimal point | ||
# Otherwise, print "0." and then print zeros so that the number of | ||
# zeros plus `coefdigits` is `pointpos` | ||
if pointpos < coefdigits | ||
print(io, @view(coef[1:end - pointpos]), ".", | ||
@view(coef[end - pointpos + 1:end])) | ||
else | ||
print(io, "0.", repeat('0', pointpos - coefdigits), coef) | ||
end | ||
end | ||
end | ||
|
||
# Show x using exponential notation | ||
function show_exponential(io::IO, x::Decimal) | ||
coef = string(x.c) | ||
coefdigits = ncodeunits(coef) | ||
|
||
if x.s | ||
print(io, '-') | ||
end | ||
|
||
# If there are more than one digit, | ||
# put a decimal point right after the first digit | ||
if coefdigits > 1 | ||
print(io, coef[1], ".", @view coef[2:end]) | ||
else | ||
print(io, coef) | ||
end | ||
|
||
adjusted_exp = x.q + coefdigits - 1 | ||
exp_sign = adjusted_exp > 0 ? '+' : '-' | ||
print(io, "E", exp_sign, abs(adjusted_exp)) | ||
end | ||
|
||
# Prints `x` using the scientific notation | ||
function scientific_notation(io::IO, x::Decimal) | ||
adjusted_exp = x.q + ndigits(x.c) - 1 | ||
|
||
# Decide whether to use the exponential notation | ||
if x.q ≤ 0 && adjusted_exp ≥ -6 | ||
show_plain(io, x) | ||
else | ||
show_exponential(io, x) | ||
end | ||
end | ||
|
||
Base.show(io::IO, x::Decimal) = print(io, "Decimal($(Int(x.s)), $(x.c), $(x.q))") | ||
Base.show(io::IO, ::MIME"text/plain", x::Decimal) = scientific_notation(io, x) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.