Evaluating Knuth's arrow notation in a function - c#

I am having trouble calculating Knuth's arrow notation, which is ↑ and can be found here, within a function. What I've made so far is:
int arrowCount = (int)arrowNum.Value; // Part of
BigInteger a = (int)aNum.Value; // the input I
BigInteger b = (int)bNum.Value; // already have
BigInteger result = a;
BigInteger temp = a;
for(int i = 0; i < arrowCount; i++)
{
result = Power(temp, b);
temp = r;
b = a;
}
with power being
BigInteger Power(BigInteger Base, BigInteger Pow)
{
BigInteger x = Base;
for(int i = 0; i < (Pow-1); i++)
{
x *= Base;
}
return x;
}
but it's incorrect with it's values and I can't figure out a way to fix it. It can handle 1 arrow problems like 3↑3 (which is 3^3 = 9), but it can't handle any more arrows than that.
I need a way to figure out more arrows, such as 3↑↑3,
which should be 7625597484987 (3^27) and I get 19683 (27^3). If you could help me to figure how I could get the proper output and explain what it is I'm doing wrong, I would greatly appreciate it.

I wrote it in java, and use double for input parameter:
private static double knuthArrowMath(double a, double b, int arrowNum)
{
if( arrowNum == 1)
return Math.pow(a, b);
double result = a;
for (int i = 0; i < b - 1; i++)
{
result = knuthArrowMath(a, result, arrowNum - 1);
}
return result;
}

If you expect 7625597484987 (3^27) but get 19683 (27^3), isn't it then a simple matter of swapping the arguments when calling your power function?
Looking at your Power function your code snippet seems to call Power with temp as base and b as power:
int arrowCount = (int)arrowNum.Value; // Part of
BigInteger a = (int)aNum.Value; // the input I
BigInteger b = (int)bNum.Value; // already have
BigInteger result = a;
BigInteger temp = a;
for(int i = 0; i < arrowCount; i++)
{
result = Power(temp, b);
temp = result;
b = a;
}
Shouldn't temp an b be swapped so you get result = Power(b, temp) to get the desired result?
So pass 1 results calls Power(3, 3) resulting in temp = 27 and pass 2 calls Power(3, 27). The reason it only works for single arrow now is because swapping arguments for the first Power(base, power) call doesn't matter.
As you point out in your answer this doesn't cover all situations. Given the examples you provided I created this little console application:
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Arrow(3, 3));
Console.WriteLine(Arrow(4, 4, 1));
Console.WriteLine(Arrow(3, 4, 1));
Console.ReadKey();
}
private static BigInteger Arrow(BigInteger baseNumber, BigInteger arrows)
{
return Arrow(baseNumber, baseNumber, arrows-1);
}
private static int Arrow(BigInteger baseNumber, BigInteger currentPower, BigInteger arrows)
{
Console.WriteLine("{0}^{1}", baseNumber, currentPower);
var result = Power(baseNumber, currentPower);
if (arrows == 1)
{
return result;
}
else
{
return Arrow(baseNumber, result, arrows - 1);
}
}
private static BigInteger Power(BigInteger number, BigInteger power)
{
int x = number;
for (int i = 0; i < (power - 1); i++)
{
x *= number;
}
return x;
}
}

I came up with a way to use the BigInteger.Pow() function.
It might look a little odd, but that is because the C# BigInterger.Pow(x, y) only accepts an int for y, and teterations have HUGE exponents. I had to "flip the script" and convert x^y = y^x for this specific case.
I didn't add in any error checking, and it expects all numbers to be positive ints.
I know this works for x^^2 and x^^3. I also know it works for 2^^4 and 2^^5. I don't have the computing power/memory/math knowledge to know if it works for any other numbers. 2^^4 and 2^^5 were the only ones I could check and test. It may work for other numbers but I was not able to confirm that.
int baseNum = 4;
int exp = 3;
// this example is 4^^3
BigInteger bigAnswer = tetration(baseNum, exp);
// Here is what the method that "does the work" looks like.
// This looks a little odd but that is because I am using BigInteger.Pow(x,y)
// Unfortunately, y can only be an int. Tetrations have huge exponents, so I had to figure out a
// way to have x^y work as y^x for this specific application
// no error checking in here, and it expects positive ints only
// I *know* this works for x^^2, x^^3, but I don't know if it works for
// any other number than 2 at ^^4 or higher
public static BigInteger tetration(int baseNum, int exp)
{
if (exp > 2)
{
exp = (int)Math.Pow(baseNum, (exp - 3));
}
else
{
exp = exp - 2;
}
Func<BigInteger, int, BigInteger> bigPowHelper = (x, y) => BigInteger.Pow(x, y);
BigInteger bigAnswer = baseNum;
for (int i = 0; i < Math.Pow(baseNum, exp); i++)
{
bigAnswer = bigPowHelper(bigAnswer, baseNum);
}
return bigAnswer;
}

Related

problems with a for-loop in C#

I am very new to C# programming (2 days in so far), after learning intermediate python and doing a few small projects, I am trying to learn C#
But because me knowing python, I am finding C# a little confusing, arrays always throw me off, while in python initializing a list is as easy as declaring a variable with empty lists x = [], C#'s way of declaring arrays is confusing.
My issue is, I encountered an error, which I did google but found nothing (there was one question similar to mine but no one had answered on it)
I was on a site called https://codewars.com/ and was solving Katas (problems) [lvl 7 (beginner)]
The question stated that for any input integer n, I have to return an array with a factor of the number n where n > 1
In python, the code will be like this:
def findFactors(n):
return [x for x in range(2, n) if n % x == 0]
So I converted the code to the best of my abilities this:
public class Kata
{
public static int[] Divisors(int n)
{
int counter = 0;
int[] myNum = {};
for (int i=2; i == n; i++) {
int calculate = n % i;
if (calculate==0) {
myNum.CopyTo(i, counter);
counter++;
}
}
if (myNum.Length == 0) {
return null;
}
else {
return myNum;
}
}
}
The error I got was:
src/Solution.cs(10,20): error CS1503: Argument 1: cannot convert from 'int' to 'System.Array'
Compared to error tracebacks in python, C# Tracebacks are a little harder to comprehend
So how can I fix this error?
To fix your code you'd need to do this:
public static int[] Divisors(int n)
{
int[] myNum = { };
for (int i = 2; i < n; i++)
{
int calculate = n % i;
if (calculate == 0)
{
int[] x = new int[myNum.Length + 1];
myNum.CopyTo(x, 0);
x[x.Length - 1] = i;
myNum = x;
}
}
return myNum;
}
But the direct equivalent to your original code is this:
public static int[] Divisors(int n)
=> Enumerable.Range(2, n - 2).Where(x => n % x == 0).ToArray();
Or using an iterator:
public static IEnumerable<int> Divisors(int n)
{
for (int i = 2; i < n; i++)
{
if (n % i == 0)
{
yield return i;
}
}
}

Decrypting RSA encoded message in C#

As an IT teacher I would like to show my students how the RSA algorithm works. I would also like to show them that 'hacking' it by iterating over all possible primes takes forever.
Encrypting and decrypting works perfectly fine for primes < 1000. When I execute the same algorithm with slightly larger primes, the decryption result is wrong.
Eg:
p, q are primes
n = p * q
phi = (p-1) * (q -1)
d = (1 + (k * phi)) / e;
**encryption:**
c = (msg ^ e) % n
**decryption**
message = c ^ d % n;
For p = 563 and q = 569 the decryption works fine.
For p = 1009 and q = 1013 on the other hand, the decrypted message =/= the original message.
I think the error is in the calculation of private exponent "d". I replaced all int's by BigIntegers, but it doesn't change a thing. Does anyone have an idea?
class RSA
{
private BigInteger primeOne;
private BigInteger primeTwo;
private BigInteger exp;
private BigInteger phi;
private BigInteger n;
private BigInteger d;
private BigInteger k;
private void calculateParameters(){
// First part of public key:
this.n = this.primeOne * this.primeTwo;
// Finding other part of public key.
this.phi = (this.primeOne - 1) * (this.primeTwo - 1);
//Some integer k
this.k = 2;
this.exp = 2;
while (this.exp < (int) this.phi)
{
// e must be co-prime to phi and
// smaller than phi.
if (gcd(exp, phi) == 1)
break;
else
this.exp++;
}
this.d = (BigInteger) (1 + (this.k * this.phi)) / this.exp; ;
}
// Return greatest common divisors
private static BigInteger gcd(BigInteger a, BigInteger b)
{
if (a == 0)
return b;
return gcd(b % a, a);
}
//Encryption algorithm RSA
public string Encrypt(string msg)
{
calculateParameters();
BigInteger encryptedNumber = BigInteger.Pow(BigInteger.Parse(msg),(int) this.exp) % this.n;
// Encryption c = (msg ^ e) % n
return Convert.ToString(encryptedNumber);
}
public string Decrypt(string encrypted)
{
BigInteger intAlphaNumber = BigInteger.Parse(encrypted);
BigInteger decryptedAlphaNumber = BigInteger.Pow(intAlphaNumber,(int) this.d) % n;
return Convert.ToString(decryptedAlphaNumber);
}
}
}
Your problem is in the math.
Recall e*d == 1 mod phi(n), which implies e*d = 1 + k*phi(n). In your implementation, you assume that k is always going to be 2. That assumption is wrong.
For proof, consider your erroneous case of p = 1009 and q = 1013. In this case, exp is 5 according to your algorithm for choosing it. The corresponding correct value of k is 4 so d should be 816077. However, your algorithm erroneous computes d as 408038.
If you put an assertion in your code to check that exp*d = 1 + k*phi(n), then you will readily see when your heuristic for k works and when it does not.
Use the extended Euclidean algorithm to get the right solution for d.
Also:
"I would also like to show them that 'hacking' it by iterating over all possible primes takes forever." Good to let them hack, and once they get frustrated and realise that it is not going to work, then you can show them that a little mathematics could have proven that to them in advance. The prime number theorem shows us the density of prime numbers. You could take for example primes on the order of 2^1024 and show them that there are on the order of 2^1014.5 primes this size. Then ask them how many tries can they do per second, and compute the number of years it would take them to crack via this naive method (or you can take the approach of looking at the storage for a table of all primes). And then that can lead into better solutions like the number field sieve. Oh so much fun!
Ok, that was very stupid of me... Thank you very much for the idea, I will certainly have a look into the theorem!
Now it works with
private static BigInteger ModInverse(BigInteger a, BigInteger n)
{
BigInteger t = 0, nt = 1, r = n, nr = a;
if (n < 0)
{
n = -n;
}
if (a < 0)
{
a = n - (-a % n);
}
while (nr != 0)
{
var quot = r / nr;
var tmp = nt; nt = t - quot * nt; t = tmp;
tmp = nr; nr = r - quot * nr; r = tmp;
}
if (r > 1) throw new ArgumentException(nameof(a) + " is not convertible.");
if (t < 0) t = t + n;
return t;
}

Why do different algorithms of summing not match?

Assume that I want to get sum of all squares from M to N. I googled a bit and found this formula:
(1^2 + 2^2 + 3^2 + ... + N^2) = (N * (N + 1) * (2N + 1)) / 6
so I write this code:
static void Main(string[] args)
{
const int from = 10;
const int to = 50000;
Console.WriteLine(SumSquares(from, to));
Console.WriteLine(SumSquares2(from, to));
}
static long SumSquares(int m, int n)
{
checked
{
long x = m - 1;
long y = n;
return (((y*(y + 1)*(2*y + 1)) - (x*(x + 1)*(2*x + 1)))/6);
}
}
static long SumSquares2(int m, int n)
{
long sum = 0;
for (int i = m; i <= n; ++i)
{
sum += i * i;
}
return sum;
}
it works fine until 40k, but when N becomes 50k it fails. Output for 50k:
41667916674715
25948336371355
Press any key to continue . . .
I think it's an overflow or something, so I added checked keyword and tried to change long to double, but I got the same result. How can it be explained? How to get correct result without loops?
Your second method is overflowing because you are using an int in the loop. Change it to a long as follows (and also add checked):
static long SumSquares2(int m, int n)
{
checked
{
long sum = 0;
for (long i = m; i <= n; ++i)
{
sum += i*i;
}
return sum;
}
}
What was going wrong is that i*i was being calculated internally as an int data type even though the result was being cast to a long data type (i.e. the variable sum), and so it overflowed.
While you are using long for the result, you are still using int for the operators. I would define M and N as long or even BigInteger, and the same for the result. If you do not, you are probably doing int arithmetic still, even though your result is of type long.
I tried your code, and got the results you got. But then I changed every int to long and got the two numbers to match, up to an N of 1600000.
Using BigInteger, I am up to 160000000 and still working ok (result for m=10 and n=160000000 is 13653333461333333359999715, both ways).
To use BigInteger, you will need to add a reference to the System.Numerics dll to your project, and you will need to have a statement at the top of your code including that library.
using System.Numerics;
namespace ConsoleFiddle
{
class Program
{
static void Main(string[] args)
{
BigInteger from = 10;
BigInteger to = 160000000;
Console.WriteLine(SumSquares(from, to));
Console.WriteLine(SumSquares2(from, to));
Console.ReadKey();
}
static BigInteger SumSquares(BigInteger m, BigInteger n)
{
checked
{
BigInteger x = m - 1;
BigInteger y = n;
return (((y * (y + 1) * (2 * y + 1)) - (x * (x + 1) * (2 * x + 1))) / 6);
}
}
static BigInteger SumSquares2(BigInteger m, BigInteger n)
{
checked
{
BigInteger sum = 0;
for (BigInteger i = m; i <= n; ++i)
{
sum += i * i;
}
return sum;
}
}
For an M of 4000000000000000000 (4 x 10^18), and an N of 4000000000100000000. This code still works and gives an immediate result with the first method (1600000016040000000400333333338333333350000000). With the second method it takes it a little while (100 million loop iterations) but gives the same result.
Most probably you are experiencing integer overflow, as the range of long is limited. Probably you have disabled exceptions for integer overflow, so no exception is thrown. The exceptions for integer overflow can be disabled and enabled in the project properties in Visual Studio, if I'm not mistaken.

itoa conversion in C#

It was an interview question asked to me - write itoa conversion without using any builtin functions.
The following is the algorithm I am using. But ('0' + n % 10); is throwing an error:
cannot convert string to int
private static string itoa(int n)
{
string result = string.Empty;
char c;
bool sign = n > 0 ? true : false;
while (true)
{
result = result + ('0' + n % 10); //'0'
n = n / 10;
if(n <= 0)
{
break;
}
}
if(sign)
{
result = result + '-';
}
return strReverse(result);
}
I'm unclear why you'd want to do this; just call ToString on your integer. You can specify whatever formatting you need with the various overloads.
As #minitech commented, we usually just use ToString() to do that in C#. If you really want to write the algorithm on your own, the following is an implementation:
public static partial class TestClass {
public static String itoa(int n, int radix) {
if(0==n)
return "0";
var index=10;
var buffer=new char[1+index];
var xlat="0123456789abcdefghijklmnopqrstuvwxyz";
for(int r=Math.Abs(n), q; r>0; r=q) {
q=Math.DivRem(r, radix, out r);
buffer[index-=1]=xlat[r];
}
if(n<0) {
buffer[index-=1]='-';
}
return new String(buffer, index, buffer.Length-index);
}
public static void TestMethod() {
Console.WriteLine("{0}", itoa(-0x12345678, 16));
}
}
It works only for int. The range int is -2147483648 to 2147483647, the length in the string representation would be max to 11.
For the signature of itoa in C is char * itoa(int n, char * buffer, int radix);, but we don't need to pass the buffer in C#, we can allocate it locally.
The approach that add '0' to the remainder may not work when the radix is greater than 10; if I recall correctly, itoa in C supports up to 36 based numbers, as this implementation is.
('0' + n % 10) results in an int value, so you should cast it back to char. There are also several other issues with your code, like adding - sign on the wrong side, working with negative values, etc.
My version:
static string itoa(int n)
{
char[] result = new char[11]; // 11 = "-2147483648".Length
int index = result.Length;
bool sign = n < 0;
do
{
int digit = n % 10;
if(sign)
{
digit = -digit;
}
result[--index] = (char)('0' + digit);
n /= 10;
}
while(n != 0);
if(sign)
{
result[--index] = '-';
}
return new string(result, index, result.Length - index);
}

a more simple big adder in c#?

I just had the task in school to write a big adder. Meaning a method that can put very large numbers together.
We had 10 minutes and I did complete it on time. The teacher approved it.
I am not too satisfied with the result though, and I thought I perhaps were taking the wrong approach.
Here is my version:
using System;
using System.Text;
namespace kæmpe_adder
{
static class Program
{
static void Main()
{
var x = "1111";
var y = "111111111";
Console.WriteLine(BigAdder(x, y));
Console.ReadLine();
}
public static StringBuilder BigAdder(string x, string y)
{
var a = new StringBuilder(x);
var b = new StringBuilder(y);
return BigAdder(a, b);
}
public static StringBuilder BigAdder(StringBuilder x, StringBuilder y)
{
int biggest;
int carry = 0;
int sum;
var stringSum = new StringBuilder();
if (x.Length > y.Length)
{
y.FillString(x.Length - y.Length);
biggest = x.Length;
}
else if (y.Length > x.Length)
{
x.FillString(y.Length - x.Length);
biggest = y.Length;
}
else
{
biggest = y.Length;
}
for (int i = biggest - 1; i >= 0; i--)
{
sum = Convert.ToInt32(x[i].ToString()) + Convert.ToInt32(y[i].ToString()) + carry;
carry = sum / 10;
stringSum.Insert(0, sum % 10);
}
if (carry != 0)
{
stringSum.Insert(0, carry);
}
return stringSum;
}
public static void FillString(this StringBuilder str, int max)
{
for (int i = 0; i < max; i++)
{
str.Insert(0, "0");
}
}
}
}
When I wrote it, I thought of how you do it with binaries.
Is there a shorter and/or perhaps simpler way to do this?
From the algebraic point of view your code looks correct. From the design point of view, you would definitely prefer to encapsulate each of these big numbers in a class, so that you don't have to reference the string/string builders all the time. I am also not a big fan of this FillString approach, it seems more reasonable to add the digits while both numbers have non-zero values, and then just add the carry to the bigger number until you are done.
Not sure what was the question about binaries? The normal length numbers (32bit and 64bit) are added by the CPU as a single operation.
There are a number of open source implementations you could look to for inspiration.
http://www.codeproject.com/KB/cs/biginteger.aspx
http://biginteger.codeplex.com/
In general, I would recommend using an array of byte or long for best performance, but the conversion from a string to the array would be non-trivial.
Store the numbers in reverse order; this makes finding equivalent places trivial.
This makes it easier to add differently sized strings numbers:
int place = 0;
int carry = 0;
while ( place < shorter.Length ) {
result.Append (AddDigits (longer[place], shorter[place], ref carry));
++place;
}
while ( place < longer.Length ) {
result.Append (AddDigits (longer[place], 0, ref carry));
++place;
}
if ( carry != 0 )
result.Append (carry.ToString ());

Categories