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 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