Используя Юлию, как отформатировать константу Авогадро (или другие числа) в инженерной нотации? - PullRequest
0 голосов
/ 02 января 2019

Инженерные обозначения отличаются от научных обозначений тем, что:

  1. Показатель степени всегда кратен 3, а

  2. Цифры вСлева от десятичной точки масштабируется в диапазоне от 1 до 999.

Мой вариант использования требует указания от 0 до 13 цифр справа от десятичной точки.Значение по умолчанию - 4.

Вот некоторые примеры:

const Avogadro = 6.022140857e23

str = eng_notation(Avogadro, digits=0)             
# str = "602E+21"

str = eng_notation(Avogadro, digits=1)             
# str = "602.2E+21"

# Default 4 digits to right of decimal point.
str = eng_notation(Avogadro)                       
# str = "602.2141E+21"  

str = eng_notation(Avogadro, digits=10)            
# str = "602.2140857000E+21"

# Negative and fractional numbers should also work.
str = eng_notation(-0.01234567, digits=7)          
# str = "-12.4567000E-03"

Есть предложения?

Изменить: я обновил требования до 0-13 цифр справа отдесятичная точка (от 0 до 15 ранее).

Ответы [ 2 ]

0 голосов
/ 02 января 2019

Используйте пакет NumericIO.jl

julia> using NumericIO

julia> const Avogadro = 6.022140857e23;

julia> formatted(Avogadro, :ENG, ndigits=4, charset=:ASCII)
"602.2E21"

julia> formatted(Avogadro, :ENG, ndigits=4)
"602.2×10²¹"
0 голосов
/ 02 января 2019

Обновленная функция 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
...