Обновленная функция eng_notation (), приведенная ниже, решает проблему.
Количество цифр справа от десятичного числа теперь ограничено от 0 до 13 цифр вместо от 0 до 15 цифр.
Вот несколько примеров:
julia> const Avogadro = 6.022140857e23
6.022140857e23
julia> eng_notation(Avogadro, digits=0)
"602E+21"
julia> eng_notation(Avogadro, digits=1)
"602.2E+21"
julia> eng_notation(Avogadro)
"602.2141E+21"
julia> eng_notation(Avogadro, digits=10)
"602.2140857000E+21"
julia> eng_notation(-0.01234567, digits=7)
"-12.3456700E-03"
julia> eng_notation(Avogadro, digits=13, plus_sign=true)
"+602.2140857000000E+21"
julia> eng_notation(floatmax(Float64), digits=13)
"179.7693134862316E+306"
julia> eng_notation(floatmin(Float64), digits=13)
"22.2507385850720E-309"
Вот обновленный код:
"""
eng_notation(num, digits=4, spec="E", plus_sign=false)
Return `num` in engineering notation where the exponent is a multiple of 3 and the
number before the decimal point ranges from 1 to 999.
# Arguments
- `num`: any subtype of `Number`. `Complex` subtypes are passed through unchanged.
Numbers greater than (in absolute value) `floatmax(Float64)`=1.7976931348623157e308
are passed through unchanged.
Numbers less than (in absolute value) `floatmin(Float64)`=2.2250738585072014e-308 and > 0.0
are passed through unchanged.
- `digits`: the number of digits to the right of the decimal point. `digits` is clipped from 0 to 13.
- `spec`: "E", 'E', "e", or 'e' sets case of the the exponent letter.
- `plus_sign`: when `true` includes a plus sign, "+", in front of numbers that are >= 0.0.
# Examples
```julia_repl
julia> const Avogadro = 6.022140857e23
6.022140857e23
julia> eng_notation(Avogadro, digits=0)
"602E+21"
julia> eng_notation(Avogadro, digits=1)
"602.2E+21"
julia> eng_notation(Avogadro)
"602.2141E+21"
julia> eng_notation(Avogadro, digits=10)
"602.2140857000E+21"
julia> eng_notation(-0.01234567, spec="e", digits=7)
"-12.3456700e-03"
julia> eng_notation(Avogadro, digits=13, plus_sign=true)
"+602.2140857000000E+21"
julia> eng_notation(floatmax(Float64), digits=13)
"179.7693134862316E+306"
julia> eng_notation(floatmin(Float64), digits=13)
"22.2507385850720E-309"
```
"""
function eng_notation(num::Number; digits=4, spec="E", plus_sign=false)
# Complex subtypes are just passed through unchanged.
if typeof(num) <: Complex; return num; end
# Values larger/smaller that Float64 limits just pass through unchanged.
if abs(num) > floatmax(Float64); return num; end # max=1.7976931348623157e308
if abs(num) < floatmin(Float64) && num != 0; return num; end # min=2.2250738585072014e-308
# Min of 0 and max of 13 digits after the decimal point (dp).
digits = digits < 0 ? 0 : digits
digits = digits > 13 ? 13 : digits
# Don't add a dp when 0 digits after dp.
dec_pt = digits == 0 ? "" : "."
spec_char = spec[1] == 'E' ? 'E' : 'e'
sign = ifelse(num < 0, "-", ifelse(plus_sign, "+", ""))
# This Julia code is modified from Java code at:
# http://www.labbookpages.co.uk/software/java/engNotation.html
# If the value is zero, then simply return 0 with the correct number of digits.
if num == 0; return string(sign, 0, dec_pt, "0"^digits, spec_char, "+00"); end
# If the value is negative, make it positive so the log10 works
pos_num = num < 0 ? -num : num
log10_num = log10(pos_num);
# Determine how many orders of 3 magnitudes the value is.
count = floor(log10_num/3);
# Scale num into the range 1 <= num < 1000.
val = num/10.0^(3count)
if digits == 0
val_int = Int(round(val, digits=0))
else
val_int = Int(trunc(val))
end
n_val_digits = length(string(val_int))
n_val_digits = ifelse(val_int < 0, n_val_digits-1, n_val_digits) # Account for - sign
# Determine fractional digits to requested number of digits.
# Use 15 below because 1 + 15 = 16, and 16 sigdigits is around the limit of Float64.
num_str = @sprintf "%+.15e" num
# Remove sign and decimal pt.
digits_str = replace(num_str[2:end], "." => "")
e_index = findlast("e", digits_str).start
# Remove exponent.
digits_str = digits_str[1:e_index-1]
# Jump over leading digits to get digits to right of dec pt.
frac_digits = digits_str[n_val_digits+1:end]
if digits == 0
frac_digits = ""
else
frac_digits = string(Int(round(parse(Int, frac_digits), sigdigits=digits)))
# Round may not give us digits zeros, so we just pad to the right.
frac_digits = rpad(frac_digits, digits, "0")
frac_digits = frac_digits[1:digits]
end
# Determine the scaled exponent and pad with zeros for small exponents.
exp = Int(3count)
exp_sign = exp >= 0 ? "+" : "-"
exp_digits = lpad(abs(exp), 2, "0")
return string(sign, abs(val_int), dec_pt, frac_digits, spec_char, exp_sign, exp_digits)
end # eng_notation()
Вот несколько тестов:
function test_eng_notation()
@testset "Test eng_notation() function" begin
Avogadro = 6.022140857e23
@test eng_notation(Avogadro, digits=0) == "602E+21"
@test eng_notation(Avogadro, digits=1) == "602.2E+21"
@test eng_notation(Avogadro) == "602.2141E+21"
@test eng_notation(Avogadro, digits=10) == "602.2140857000E+21"
@test eng_notation(-0.01234567, spec="e", digits=7) == "-12.3456700e-03"
@test eng_notation(Avogadro, digits=13, plus_sign=true) == "+602.2140857000000E+21"
@test eng_notation(floatmax(Float64), digits=13) == "179.7693134862316E+306"
@test eng_notation(floatmin(Float64), digits=13) == "22.2507385850720E-309"
end
return nothing
end