Is there any packages to fast change numerical base, like to binary or octal, without using a custom function?
I have some algorithms that I coded myself, but definitely there is faster algorithms to do so. Any help?
I need a function to change a number’s base, do arithmetics with the number and if possible to analyze this number, like a function thats returns the 3° digit of the number etc.
Base is a property of how a number is displayed, not of of the number itself or of how you do arithmetic. You can display the digits of a number in any base you want using the digits function;
You can use the digits function for this, but it’s not optimal, because it calculates all the digits and puts them in a vector. Here’s a faster version:
function getdigit(n::Integer, digit::Integer; base=10)
digit < 1 && error("Digit must be positive number.")
m = (ndigits(n; base=base) - digit + 1)
d = 0
for i in 1:m
n, d = divrem(n, base)
end
return d
end
You can do better than this. Instead of repeated divrem, you can use one log, mod, and div to get arbitrary digits in O(1) (technically it’s something more complicated for BigInt, but it still should be exponentialy faster.)
I don’t immediately see how to use log, but here’s an O(1) version that is pretty fast:
function getdigit_(n::Integer, digit::Integer; base=10)
digit < 1 && error("Digit must be positive number.")
m = (ndigits(n; base=base) - digit + 1)
d = divrem(n, base^(m-1))[1]
return divrem(d, base)[2]
end
Edit: The above will fail in some cases, we must keep track of the integer type. Here’s better version, but it is still virtually untested, caveat emptor!
Also, note that it is O(1) in the selection of the digit, but not O(1) in the size of the number n.
function getdigit_(n::T, digit::Integer; base=10) where {T<:Integer}
digit < 1 && error("Digit must be positive number.")
m = (ndigits(n; base=base) - digit + 1)
d = divrem(n, T(base)^(m-1))[1]
return divrem(d, base)[2]
end
So, actually, when the base is a power of 2, it is much faster to use digits (Edit: this happens for number types other than Int, so there is some weakness in how those are handled). So this fixes that, and is faster than digits also for power-of-2:
function getdigit(n::T, digit::Integer; base=10) where {T<:Integer}
digit < 1 && error("Digit must be positive number.")
if ispow2(base)
return _getdigit_pow2(n, digit, base)
end
m = (ndigits(n; base=base) - digit + 1)
d = divrem(n, T(base)^(m-1))[1]
return divrem(d, base)[2]
end
function _getdigit_pow2(n::T, digit::Integer, base) where {T<:Integer}
base = Int(base)
m = (ndigits(n; base=base) - digit + 1)
k = trailing_zeros(base)
c = base - 1
d = (abs(n) >> (k * (m - 1))) & c
return copysign(d, n)
end
(Credit: the code in _getdigit_pow2 is directly based on code from Base.digits!)