Fastest way to get the first 5 digits of a BigInteger - c#

Suppose n is a BigInteger and I want its first 5 digits. I'm thinking in 2 ways:
Dividing n by 10 log10(n)-5 times (so only the first 5 digits would remain).
Get the Substring(0, 5) of n's string.
I have no idea which one is faster or if there is another option that may be better than these.
I would like to hear considerations about it before I test these options (what do you think of them, if there is something better, etc.).

If we want to find out first 5 leading digits, we can exploit integer division:
123 / 1 == 123
12345 / 1 == 12345
1234567 / 100 == 12345
Naive approach is to divide original value by 10 while it is bigger or equal 1_000_000:
1234567 => 123456 => 12345
However, division is expensive especially if we have a huge number (if we have a number with ~1000000 digits we have to divide this number ~1000000 times). To create a faster solution
we can compute an appropriate power of 10 (power computation is fast) and then divide just once:
1234567 / Pow(10, Log10(1234567) - 5 + 1)
So the raw idea is
result = source / BigInteger.Pow(10, (int)BigInteger.Log10(source) - 4);
There are two difficulties here:
Negative numbers (we should take absolute value of source at least when we computing logarithms)
Rounding errors for huge source (what if we have rounding up and have just 4 digits?)
To cope with both problems I compute Log10 myself as Log10(2) * Log2(source):
value.GetBitLength() * 0.30102999566398
this guarantees that I have at least 5 digits but may be 6 in case of rounding errors (note 0.30102999566398 < Log10(2)).
Combining all together:
private static int FirstDigits(BigInteger value) {
if (value.IsZero)
return 0;
int digits = 5;
int result = (int)(value /
BigInteger.Pow(10, (int)(value.GetBitLength() * 0.30102999566398 - digits + 1)));
while (result >= 1_000_000 || result <= -1_000_000)
result /= 10;
return result;
}

Related

c sharp finding a specific digit in an int [duplicate]

This question already has answers here:
Get the seventh digit from an integer
(9 answers)
Get individual digits from an Int without using strings?
(1 answer)
Closed 4 years ago.
I'm trying to find the nth digit of an integer (from right to left). I'm new to programming but have been using this site a lot for reference - up until now I've resisted passing my problems on but I cannot understand this one in the least, even after hours of effort.
This is the code I have so far but for FindDigit(int 5673, int 4) it gives 53 instead of 5, FindDigit(int 5673, int 3) gives 51 instead of 6
public class DigitFinder
{
public static int FindDigit(int num, int nth)
{
num = Math.Abs(num);
string answer = Convert.ToString(num);
int i = answer.Length;
return ans[i-nth];
}
}
I cannot understand at all why it returns a 2 digit number. Any guidance at all appreciated!
I'd just use
int result = (num / (int)Math.Pow(10,nth-1)) % 10;
Where num is the number to get the nth digit from (counted right to left) and nth is the "index" of digits you want (again: counted from right to left). Mind that it is 1-based. That is "1" is the rightmost digit. "0" would be out of range.
To explain the math:
(int)Math.Pow(10,nth-1) takes your desired index and decreases it by 1, then takes that as the power of 10. So if you want the 3rd digit, that makes 10 to the power of two equals 100.
BTW: the cast to int is necessary because Math.Pow works on double and returns double. But we want to keep on working in integer arithmetic.
Dividing by the result of above equation "shifts" your number to the right, so your desired digit becomes the rightmost digit. Example: 1234, we want 3rd digit from right ("2") => 1234 / (10^(3-1))= 1234 / 100 = 12
You then "cut out" that rightmost digit by applying the "remainder" (modulo) operator with divisor 10. Example: 12 % 10 = [12 / 10 = 1, Remainder =] 2.
Mind that I also would check nth to be > 0 and num >= 10 ^ (nth-1). (never trust user input)
53 is the ASCII code of the character 5. Just subtract the character 0, i.e. numeric 48.
However, it is usually a good idea to avoid string manipulation for things like this; if possible you should probably prefer division/remainder (modulo) arithmetic.
Just because no one else did, and also because i have Printable Character OCD
public static int GetLeastSignificantDigit(int number, int digit)
{
for (var i = 0; i < digit - 1; i++)
number /= 10;
return number % 10;
}
Demo here

C# - Constantly adding 9 digits

As the title says, I'm developing in C#.
I'd like to generate a number which has more than 9 numbers, so I thought about generating numbers, follow by 9.
For instance, if I want to generate a number which has 10 digits - I'd generate first a number which has 9 numbers, and then a number which has 1 digit.
If I generate the number 20, I'd generate first 2 numbers with 9 digits each, and then a number with 2 digits.
This is what I've tried:
for (int i = 0, j = (int.Parse(inputRandom.Text) % 9 == 0 ? int.Parse(inputRandom.Text) % 9 : int.Parse(inputRandom.Text) % 9 + 1); i < j; i++)
if (i < (int.Parse(inputRandom.Text) % 9 == 0 ? j % 9 : j % 9 + 1) - 1)
numToSend += (BigInteger)r.Next(int.Parse(1 + Zero((int.Parse(inputRandom.Text) % 9 + 8) * (inputRandom.Text.Length - 1))));
else
numToSend += (BigInteger)r.Next(int.Parse(1 + Zero(int.Parse(inputRandom.Text) % 9 * 9)));
The method Zero returns a string with 0, times the number specified in. I.e Zero(1) would return: "0"
I need this method because the method Next(Int32) can return a number, up to what specified between the brackets. I.e Next(10) would return a number between 0 and 9.
My goal
I want to generate a number with a number of digit above 9, and put the number into the string numToSend. I cannot simply do this, because the method Next() can only generate ints.
Even after your edit, I don't find the question very clear. However, I do think I understand that you are essentially trying to generate a random BigInteger value, and that you want the random value to be within a range defined by some specific number of digits.
For example, if you ask for a 10-digit value, some value between 0 and 9999999999 should be returned. If you ask for a 20-digit value, some value between 0 and 99999999999999999999 should be returned.
Based on that understanding, I believe this method should accomplish what you are asking:
BigInteger NextRandom(Random random, int digitCount)
{
BigInteger result = 0;
while (digitCount-- > 0)
{
result = result * 10 + random.Next(10);
}
return result;
}
Note that the number returned could have fewer than digitCount actual digits in it. In fact, there's always a 1-in-10 chance of that happening. And a 1-in-100 chance of the result having fewer than (digitCount - 1) digits, etc.
If you want something different from that, please be more specific about the exact requirements of the output you want (read https://stackoverflow.com/help/how-to-ask for advice on how to present your question in a clear, answerable way).
For example, the above won't generate a random value within some arbitrary range; the (exclusive) max value can only ever be a power of 10. Also, due to the way BigInteger works, if you are looking for a value with a specific number of binary digits, you can do that simply by using the Random.NextBytes() method, passing the resulting array (making modifications as appropriate to ensure e.g. positive values).
See also C# A random BigInt generator for more inspiration (I would've voted as that for a duplicate, but it seems from your description that you might be looking for a slightly different result than what's requested in that question).

C# formula to determine index

I have a maths issue within my program. I think the problem is simple but I'm not sure what terms to use, hence my own searches returned nothing useful.
I receive some values in a method, the only thing I know (in terms of logic) is the numbers will be something which can be duplicated.
In other words, the numbers I could receive are predictable and would be one of the following
1
2
4
16
256
65536
etc
I need to know at what index they appear at. In othewords, 1 is always at index 0, 2 at index 1, 4 at index 3, 16 is at index 4 etc.
I know I could write a big switch statement but I was hoping a formula would be tidier. Do you know if one exists or any clues as the names of the math forumula's I'm using.
The numbers you listed are powers of two. The inverse function of raising a number to a power is the logarithm, so that's what you use to go backwards from (using your terminology here) a number to an index.
var num = 256;
var ind = Math.Log(num, 2);
Above, ind is the base-2 logarithm of num. This code will work for any base; just substitute that base for 2. If you are only going to be working with powers of 2 then you can use a special-case solution that is faster based on the bitwise representation of your input; see What's the quickest way to compute log2 of an integer in C#?
Try
Math.Log(num, base)
where base is 2
MSDN: http://msdn.microsoft.com/en-us/library/hd50b6h5.aspx
Logarithm will return to You power of base from you number.
But it's in case if your number really are power of 2,
otherwise you have to understand exactly what you have, what you need
It also look like numbers was powered to 2 twice, so that try this:
private static int getIndexOfSeries(UInt64 aNum)
{
if (aNum == 1)
return 0;
else if (aNum == 2)
return 1;
else
{
int lNum = (int)Math.Log(aNum, 2);
return 1+(int)Math.Log(lNum, 2);
}
}
Result for UInt64[] Arr = new UInt64[] { 1, 2, 4, 16, 256, 65536, 4294967296 } is:
Num[0] = 1
Num[1] = 2
Num[2] = 4
Num[3] = 16
Num[4] = 256
Num[5] = 65536
Num[6] = 4294967296 //65536*65536
where [i] - index
You should calculate the base 2 logarithm of the number
Hint: For the results:
0 2
1 4
2 16
3 256
4 65536
5 4294967296
etc.
The formula is, for a give integer x:
Math.Pow(2, Math.Pow(2, x));
that is
2 to the power (2 to the power (x) )
Once the formula is known, one could solve it for x (I won't go through that since you already got an answer).

How does this C# code work out the answer?

I have solved the project Euler problem 16 but discovered this rather novel approach but I cannot get my head around the technique employed (from http://www.mathblog.dk/project-euler-16/):
int result = 0;
BigInteger number = BigInteger.Pow(2, 1000);
while (number > 0) {
result += (int) (number % 10);
number /= 10;
}
My version seems more conventional but I think the above approach is cooler.
var result = BigInteger
.Pow(2, 1000)
.ToString()
.Aggregate(0, (total, next) => total + (int) Char.GetNumericValue(next));
How does the mathematics work on the first approach, it is cool, but I need some explanation to help me understand, so if someone would be so kind to explain to me I would really appreciate it.
NOTE: If I have posted in the wrong section please let me know the better place to ask.
value % 10 will return the last digit (remainder after dividing by 10). Dividing the integer by 10 will remove this number.
Think of the number as a list, and you're just dequeuing the list and summing the values.
The modulus operator provides the remainder from the division. So, mod 10 is going to be the one's place in the number. The integer division by 10 will then shift everything so it can be repeated.
Example for the number 12345:
12345 % 10 = 5
12345 / 10 = 1234
1234 % 10 = 4
1234 / 10 = 123
123 % 10 = 3
123 / 10 = 12
12 % 10 = 2
12 / 10 = 1
1 % 10 = 1
1 / 10 = 0 (loop ends)
The addition is performed on the result of each modulus so you'd get 5+4+3+2+1
number % 10 extracts the least significant decimal digit. e.g. 12345 => 5
number / 10 removes the least significant decimal digit. This works because integer division in C# throws away the remainder. e.g. 12345 => 1234
Thus the above code extracts each digit, adds it to the sum, and then removes it. It repeats the process until all digits have been removed, and the number is 0.
It's quite simple:
Imagine this:
number = 54
It uses modulo to get the remainder of this divded by 10
e.g. 54 / 10 = 5 remainder 4
It then adds this digit (4) to the result, then divides the number by 10 (storing into int which discards decimal places)
so then number = 5
same again, 5 / 10 = 0 remainder 5
Adds them togther, result is now 9
and so on until the number is 0 :)
(in this case 9 is the answer)
They found the number 2^1000.
Modulo 10 gets the least significant digit.
E.G. 12034 % 10 = 4
Dividing by 10 strips the least significant digit.
E.G. 12034 / 10 = 1203
They sum up these least significant digits.

How to remove a number from another number using bitwise operators?

How do I remove for example 2 from 123 and returns 13, by using bitwise operators? I have no idea how to do this.. it's possible? Thanks in advance.
What you're suggesting is possible, but wouldn't really make sense to do. Below are the values representations in bits (only showing relevant bits, everything further left is a zero):
2: 000010 || 123: 1111011 || 13: 001101
There's no logical way to change 123 into 13 with bitwise operations. It would better to turn it into a string or character array, remove the two then cast it back to an int.
What other cases are there? It may be possible to generalize this at an integer level if there is some sort of pattern, otherwise you're really just looking at string replacement.
The 2 in 123 is actually 2E1 (10100), and the 2 in 1234 would be 2E2 (11001000) neither of which are related to 2 (10), at least in bitwise form. Also, the "number" on the right side of the removed number would need to be added to the number on the left side of the removed number / 10.
i.e, to go from 123 to 13:
Located "2".
Number on left (x): 100
Number on right (y): 3
y + (x / 10) = 13
and to go from 1324 to 134
Located "2"
Number on left (x): 1300
Number on right (y): 4
y + (x / 10) = 134
Unless there's some pattern (i.e you know what positions the numbers are in), you'll just have to .ToString() the number, then do a .Replace("2", ""), before doing an int.Parse() on the result.
EDIT: Someone upvoted this answer and I realised my previous implementation was unnecessarily complicated. It is relatively straightforward to 'iterate' over the digits in a base-10 number and shouldn't require recursion.
New solution below, performance is better but this is a huge micro-optimisation:
static int OmitDigit(int number, int digit) {
var output = 0;
var multiplier = 1;
while (number > 0) {
var n = number % 10;
number /= 10;
if (n != digit) {
output += (n * multiplier);
multiplier *= 10;
}
}
return output;
}
Result:
1554443
Since we're working with base 10 numbers, manipulation in base 2 is ugly to say the least. Using some math, removing the nth digit from k, and shifting over is
(k/pow(10,n))*pow(10, n-1) + k%pow(10, n-1)
In base 2, the << and >> operator acts like multiplying by a pow(2, n), and & with a mask does the work of %, but in base 10 the bits don't line up.
This is very awkward, but if you really do must have bitwise operations only, I suggest you convert the number to BCD. Once in BCD, you basically have an hexadecimal numbers with digits between 0 and 9, so removing a digit is very simple. Once you're done, convert back to binary.
I don't believe anybody would want to do that.

Categories

Resources