Skip to content

Commit ca33748

Browse files
committed
WIP new parser
1 parent 8233b75 commit ca33748

File tree

5 files changed

+789
-87
lines changed

5 files changed

+789
-87
lines changed

Project.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ uuid = "fb4d412d-6eee-574d-9565-ede6634db7b0"
33
authors = ["Fengyang Wang <[email protected]>", "Curtis Vogt <[email protected]>"]
44
version = "0.4.2"
55

6+
[deps]
7+
Parsers = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
8+
69
[compat]
710
julia = "1.6"
811

src/FixedPointDecimals.jl

Lines changed: 8 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ module FixedPointDecimals
2828
export FixedDecimal, RoundThrows
2929

3030
using Base: decompose, BitInteger
31+
import Parsers
3132

3233
# floats that support fma and are roughly IEEE-like
3334
const FMAFloat = Union{Float16, Float32, Float64, BigFloat}
@@ -100,6 +101,13 @@ end
100101

101102
const FD = FixedDecimal
102103

104+
include("parse.jl")
105+
106+
function __init__()
107+
append!(_BIGINT_10s, [BigInt(0) for i in 0:Threads.nthreads()])
108+
append!(_BIGINT_Rs, [BigInt(0) for i in 0:Threads.nthreads()])
109+
end
110+
103111
(::Type{T})(x::Real) where {T <: FD} = convert(T, x)
104112

105113
floattype(::Type{<:FD{T}}) where {T<:Union{Int8, UInt8, Int16, UInt16}} = Float32
@@ -413,77 +421,6 @@ function Base.show(io::IO, x::FD{T, f}) where {T, f}
413421
end
414422
end
415423

416-
# parsing
417-
418-
"""
419-
RoundThrows
420-
421-
Raises an `InexactError` if any rounding is necessary.
422-
"""
423-
const RoundThrows = RoundingMode{:Throw}()
424-
425-
function Base.parse(::Type{FD{T, f}}, str::AbstractString, mode::RoundingMode=RoundNearest) where {T, f}
426-
if !(mode in (RoundThrows, RoundNearest, RoundToZero))
427-
throw(ArgumentError("Unhandled rounding mode $mode"))
428-
end
429-
430-
# Parse exponent information
431-
exp_index = something(findfirst(==('e'), str), 0)
432-
if exp_index > 0
433-
exp = parse(Int, str[(exp_index + 1):end])
434-
sig_end = exp_index - 1
435-
else
436-
exp = 0
437-
sig_end = lastindex(str)
438-
end
439-
440-
# Remove the decimal place from the string
441-
sign = T(first(str) == '-' ? -1 : 1)
442-
dec_index = something(findfirst(==('.'), str), 0)
443-
sig_start = sign < 0 ? 2 : 1
444-
if dec_index > 0
445-
int_str = str[sig_start:(dec_index - 1)] * str[(dec_index + 1):sig_end]
446-
exp -= sig_end - dec_index
447-
else
448-
int_str = str[sig_start:sig_end]
449-
end
450-
451-
# Split the integer string into the value we can represent inside the FixedDecimal and
452-
# the remaining digits we'll use during rounding
453-
int_end = lastindex(int_str)
454-
pivot = int_end + exp - (-f)
455-
456-
a = rpad(int_str[1:min(pivot, int_end)], pivot, '0')
457-
b = lpad(int_str[max(pivot, 1):int_end], int_end - pivot + 1, '0')
458-
459-
# Parse the strings
460-
val = isempty(a) ? T(0) : sign * parse(T, a)
461-
if !isempty(b) && any(!isequal('0'), b[2:end])
462-
if mode == RoundThrows
463-
throw(InexactError(:parse, FD{T, f}, str))
464-
elseif mode == RoundNearest
465-
val += sign * parse_round(T, b, mode)
466-
end
467-
end
468-
469-
reinterpret(FD{T, f}, val)
470-
end
471-
472-
function parse_round(::Type{T}, fractional::AbstractString, ::RoundingMode{:Nearest}) where T
473-
# Note: parsing each digit individually ensures we don't run into an OverflowError
474-
digits = Int8[parse(Int8, d) for d in fractional]
475-
for i in length(digits):-1:2
476-
if digits[i] > 5 || digits[i] == 5 && isodd(digits[i - 1])
477-
if i - 1 == 1
478-
return T(1)
479-
else
480-
digits[i - 1] += 1
481-
end
482-
end
483-
end
484-
return T(0)
485-
end
486-
487424

488425
"""
489426
max_exp10(T)

0 commit comments

Comments
 (0)