Find number of digits in a non-integer number?

Hello!

Say I have four numbers; 1.0 0.5 0.05 0.065

I want to know how far I have to go before I hit the first non-zero value. So in this case;

For 1 I would not have to move, so I expect to get output, 0
For 0.5 I would have to move once, so I expect to get output, 1
For 0.05, I would have to move twice, so I expect to get output, 2

And lastly for 0.065, I would expect to get ouput, 2, as I did with 0.05.

I have tried using the “digits” and “ndigits” functionality but they seem to only work for integers - does this kind of function I seek exist in Julia natively or do I have to do something with string manipulation?

Kind regards

Although it is not exposed API so it may change, you may find the second value from Base.Ryu.reduce_shortest useful.

1 Like
ilog10(x) = Int(floor(log10(x)))
alog10(x) = abs(ilog10(x))

to_nonzero_digit(x::Integer) = 0

function to_nonzero_digit(x::AbstractFloat)
    !isfinite(x) && throw(DomainError(x, "expected a finite value"))
    if isinteger(x)
        0
    else
        alog10(abs(x))
    end
end
ns=(1.0, 0.5, 0.05, 0.0625, 0.001, 0.0025)
to_nonzero_digit.(ns) == (0, 1, 2, 2, 3, 3)
7 Likes

I was not able to find it, maybe because I am using Julia v1.2 or that I did not import it properly?

Kind regards

Thanks, exactly what I wanted

Kind regards

It is more recent (you need at least 1.3, but then why not go to 1.4). The result should be identical to @JeffreySarnoff’s solution though.

I see, thanks for making me aware of it :slight_smile: Just downloaded v1.4.

Kind regards

In older Julia versions, x -> 1 - Base.Grisu.grisu(x, Base.Grisu.PRECISION, 4)[2] would serve the same purpose I believe.

2 Likes

Thanks for the suggestion!

I ended up making a modified version, as such;

to_nonzero_digit(x::Integer) = 0

function to_nonzero_digit(x::AbstractFloat)
    !isfinite(x) && throw(DomainError(x, "Expected a finite value"))
    test = 1 - Base.Grisu.grisu(x, Base.Grisu.PRECISION, 4)[2];
    if test < 0
        val = 0;
    else
        val = test;
    end
end

Which should work for any number, atleast the ones in the range of 0 to 100.

Kind regards

Does to_nonzero_digit(0) work for you or should you special case it / through an error?

Due to an error, since the other method only takes in an abstract float - if you input “2” without this special case, then it would error out.

Kind regards

That is not what I mean, I wonder if to_nonzero_digit(0) should return something else than 0?

Oh sorry, read to fast. Yes, ideally it should throw an error, since in my use case it should not be allowed. That would be good to add to it actually.

The only values for x which should be allowed are real positive numbers, is there a smart way to specify that condition?

Kind regards

Not as elegant as that of Jeffrey S., but perhaps more performing, if it were relevant

function count_dgtz(x)
    zs=0.
    while x <1.
        x*=10.
        zs+=1
    end
    return zs
end

a few different tips, using string functions, which are much slower:

function count_dgtz2(x)
    x=string(x)
    tot=replace(x,'.'=>"")
    lt=length(tot)
    lnz=length(lstrip(tot,'0'))
    return lt-lnz
end
function count_dgtz3(x) 
    x>1 ? 0 : findfirst(x->x>'0',string(x))-2
end

I have experienced that the solutions that use string functions have the problem of “translation” in exponential format of some real numbers.

julia> function count_dgtz3(x)
           x>1 ? 0 : findfirst(x->x>'0',string(x))-2
           end
count_dgtz3 (generic function with 1 method)

julia> x=0.00000000060007
6.0007e-10

julia> count_dgtz3(x)
-1



julia> x=0.0060007
0.0060007

julia> count_dgtz3(x)
3



Is it possible somehow to get a string with the same form “0.000000000007” from a number 0.000000000007?

What follow would be a workaround to overcome the exponential format problem

function count_dgtz4(x)
    if x > 1
        return 0
    elseif x <10.e-5
        return parse(Int,last(split(string(x),'-')))
    else
        s=string(x)
        return match(r"(0[1-9])|(\.[1-9])", s).offset-1
    end
end

julia> x=0.00000000060007
6.0007e-10

julia> count_dgtz4(x)
10

@rocco_sprmnt21, you could use: @sprintf