reversing this math expression in C# - c#

I have a lot of dislikes on this post, I'm not sure why, but for letting you guys help me out with this question, I will give you this script as a gift. This script converts experience to level and from level to experience points given an exponential expression. those constants ensure that level 100 will equal 10 million experience. In Runescape, their level 99 equals 13,032,xxx which is a strange number.
using System.IO;
using System;
class Program
{
const float salt = 2.82842712474619f;
const float factor = 0.64977928f;
const int lvl_100_XP = 10000000;
static void Main()
{
int xp = 9717096;// lvl 99
int lvl = ExperienceToLevel(xp);
Console.WriteLine("LVL: " + lvl.ToString()+ " XP: " + LevelToExperience(lvl).ToString());
}
static public int ExperienceToLevel(int xp){
int lvl = 0;
if (xp == lvl_100_XP){//9999987 is lvl 100 due to roundoff issues so it is fixed to 10mill
lvl = 100;
}
else{
lvl = (int)((1f / salt) * (float)Math.Pow((float)xp, (1f - factor)));
if (lvl == 0){
//lvl = 1;
}
}
if (lvl == 100 && xp < lvl_100_XP){
lvl = 99;
}
return lvl;
}
static public int LevelToExperience(int lvl){
int xp = 0;
if (lvl == 100){//9999987 is lvl 100 due to roundoff issues so it is fixed to 10mill
xp = lvl_100_XP;
}
else{
xp = (int)Math.Exp((float)Math.Log(salt * (float)lvl) / (1f - factor))+1;
if (xp <= 1){
xp= 0;
}
if (lvl == 100){
xp = lvl_100_XP;
}
}
return xp;
}
}

Let's work it out.
Let x be the experience, a and c are constants. L is the level. We notate exponentiation as ^; note that C# does not have such an operator. ^ in C# is XOR.
You have
b = x / a
d = x ^ c
L = b / d
so that's
L = x / (a * x ^ c)
which is
L = (1 / a) * (x / x ^ c)
which is
L = (1 / a) * x ^ (1 - c)
You wish to solve for x. So multiply both sides by 'a':
a * L = x ^ (1 - c)
Take the ln of both sides. (Or whatever logarithm you like best.)
ln (a * L) = (1 - c) ln (x)
Divide both sides by 1 - c
ln (a * L) / (1 - c) = ln x
And eliminate the ln; remember that exp is the inverse of ln. If you used some other logarithm, then use some other exponent.
exp (ln (a * L) / (1 - c)) = x
And we're done.

First of all, exp to level is a many to one relationship. The reverse is a one to many, so what exp are you aiming to return in lvl2exp? The minimum for that level? The maximum? A mean value?
I think your better off just computing once a table with experience brackets for each level (even cache it to a file if its not going to change) and simply doing a binary search to find the corresponding bracket for any given level.

Related

C# Decimal Precision Improvement in Powers and Fibonacci

I am trying to solve the Fibonacci sequence with both negative numbers and large numbers and came up with the following code and algorithm. I am certain the algorithm works, but the issue I am having is for very large numbers the precision of the result is incorrect. Here is the code:
public class Fibonacci
{
public static BigInteger fib(int n)
{
decimal p = (decimal) (1 + Math.Sqrt(5)) / 2;
decimal q = (decimal) (1 - Math.Sqrt(5)) / 2;
decimal r = (decimal) Math.Sqrt(5);
Console.WriteLine("n: {0} p: {1}, q: {2}, t: {3}",
n,
p,
q,
(Pow(p, n) - Pow(q, n)) / r);
return (BigInteger) (Decimal.Round((Pow(p, n) - Pow(q, n)) / r));
}
public static decimal Pow(decimal x, int y)
{
if(y < 0)
return 1 / Pow(x, -1 * y);
else if(y == 0)
return 1;
else if(y % 2 == 0)
{
decimal z = Pow(x, y / 2);
return z * z;
}
else if(y % 2 == 1)
return Pow(x, y - 1) * x;
else
return 1;
}
Small values of If we take a large number like -96 to get the Fibonacci for, I get a result of -51680708573203484173 but the real number is -51680708854858323072. I checked the rounding was OK, but it appears somewhere along the way my result is losing precision and not saving its values correctly. I thought using decimals would solve this precision issue (previously used doubles), but that did not work.
Where in my code am I incorrectly missing precision or is there another issue with my code I am misdiagnosing?
Try this.
public static BigInteger Fibonacci(int n)
{
BigInteger a = 0;
BigInteger b = 1;
for (int i = 31; i >= 0; i--)
{
BigInteger d = a * (b * 2 - a);
BigInteger e = a * a + b * b;
a = d;
b = e;
if ((((uint)n >> i) & 1) != 0)
{
BigInteger c = a + b;
a = b;
b = c;
}
}
return a;
}
Good Luck!
As you wrote, decimal has approximately 28 decimal digits of precision. However, Math.Sqrt(5), being a double, does not.
Using a more accurate square root of 5 enables this algorithm to stay exact for longer, though of course it is still limited by precision eventually, just later.
public static BigInteger fib(int n)
{
decimal sqrt5 = 2.236067977499789696409173668731276235440618359611525724270m;
decimal p = (1 + sqrt5) / 2;
decimal q = (1 - sqrt5) / 2;
decimal r = sqrt5;
return (BigInteger) (Decimal.Round((Pow(p, n) - Pow(q, n)) / r));
}
This way fib(96) = 51680708854858323072 which is correct. However, it becomes wrong again at 128.

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 this sin(x) function in C# return NaN instead of a number

I have this function wrote in C# to calc the sin(x). But when I try with x = 3.14, the printed result of sin X is NaN (not a number),
but when debugging, its is very near to 0.001592653
The value is not too big, neither too small. So how could the NaN appear here?
static double pow(double x, int mu)
{
if (mu == 0)
return 1;
if (mu == 1)
return x;
return x * pow(x, mu - 1);
}
static double fact(int n)
{
if (n == 1 || n == 0)
return 1;
return n * fact(n - 1);
}
static double sin(double x)
{
var s = x;
for (int i = 1; i < 1000; i++)
{
s += pow(-1, i) * pow(x, 2 * i + 1) / fact(2 * i + 1);
}
return s;
}
public static void Main(String[] param)
{
try
{
while (true)
{
Console.WriteLine("Enter x value: ");
double x = double.Parse(Console.ReadLine());
var sinX = sin(x);
Console.WriteLine("Sin of {0} is {1}: " , x , sinX);
Console.ReadLine();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
It fails because both pow(x, 2 * i + 1) and fact(2 * i + 1) eventually return Infinity.
In my case, it's when x = 4, i = 256.
Note that pow(x, 2 * i + 1) = 4 ^ (2 * 257) = 2.8763090157797054523668883052624395737887631663 × 10^309 - a stupidly large number which is just over the max value of a double, which is approximately 1.79769313486232 x 10 ^ 308.
You might be interested in just using Math.Sin(x)
Also note that fact(2 * i + 1) = 513! =an even more ridiculously large number which is more than 10^1000 times larger than the estimated number of atoms in the observable universe.
When x == 3.14 and i == 314 then you get Infinity:
?pow(-1, 314)
1.0
?pow(x, 2 * 314 + 1)
Infinity
? fact(2 * 314 + 1)
Infinity
The problem here is an understanding of floating point representation of 'real' numbers.
Double numbers while allowing a large range of values only has a precision of 15 to 17 decimal digits.
In this example we are calculating a value between -1 and 1.
We calculate the value of the sin function by using the series expansion of it which is basically a the sum of terms. In that expansion the terms become smaller and smaller as we go along.
When the terms have reached a value less than 1e-17 adding them to what is already there will not make any difference. This is so because we only have 52 bit of precision which are used up by the time we get to a term of less than 1e-17.
So instead of doing a constant 1000 loops you should do something like this:
static double sin(double x)
{
var s = x;
for (int i = 1; i < 1000; i++)
{
var term = pow(x, 2 * i + 1) / fact(2 * i + 1);
if (term < 1e-17)
break;
s += pow(-1, i) * term;
}
return s;
}

Dealing with large integers without BigInteger Library in Algorithm contests

Problem: Topcoder SRM 170 500
Consider a sequence {x0, x1, x2, ...}. A relation that defines some term xn in terms of previous terms is called a recurrence relation. A linear recurrence relation is one where the recurrence is of the form xn = c(k-1) * x(n-1) + c(k-2) * x(n-2) + ... + c(0) * x(n-k)
where all the c(i) are real-valued constants, k is the length of the recurrence relation, and n is an arbitrary positive integer which is greater than or equal to k.
You will be given a int[] coefficients, indicating, in order, c(0), c(1), ..., c(k-1). You will also be given a int[] initial, giving the values of x(0), x(1), ..., x(k-1), and an int N. Your method should return xN modulo 10.
More specifically, if coefficients is of size k, then the recurrence relation will be
xn = coefficients[k - 1] * xn-1 + coefficients[k - 2] * xn-2 + ... + coefficients[0] * xn-k.
For example, if coefficients = {2,1}, initial = {9,7}, and N = 6, then our recurrence relation is xn = xn-1 + 2 * xn-2 and we have x0 = 9 and x1 = 7. Then x2 = x1 + 2 * x0 = 7 + 2 * 9 = 25, and similarly, x3 = 39, x4 = 89, x5 = 167, and x6 = 345, so your method would return (345 modulo 10) = 5.
Constraints:
- Code must run in less than or equal to 2 seconds
- Memory utilization must not exceed 64 MB
My attempted Solution:
class RecurrenceRelation
{
public int moduloTen(int[] coefficients, int[] initial, int N)
{
double xn = 0; int j = 0;
int K = coefficients.Length;
List<double> xs = new List<double>(Array.ConvertAll<int, double>(initial,
delegate(int i)
{
return (double)i;
}));
if (N < K)
return negativePositiveMod(xs[N]);
while (xs.Count <= N)
{
for (int i = xs.Count - 1; i >= j; i--)
{
xn += xs[i] * coefficients[K--];
}
K = coefficients.Length;
xs.Add(xn);
xn = 0;
j++;
}
return negativePositiveMod(xs[N]);
}
public int negativePositiveMod(double b)
{
while (b < 0)
{
b += 10;
}
return (int)(b % 10);
}
}
My problem with this solution is the precision of the double representation, and since I can't use a third party library or the BigInteger library in .NET for this SRM, i need to find a way of solving it without them. I suspect I could use recursion but I'm a little clueless on how to go about that.
Here is a test case that shows when my code works and when it doesn't
{2,1}, {9,7}, 6 - Successfully returns 5
{9,8,7,6,5,4,3,2,1,0}, {1,2,3,4,5,6,7,8,9,10}, 654 - Unsuccessfully returns 8 instead of 5 due to precision of double type
Can anyone help me figure this out? I was going to consider using arrays to store the values but it is a little bit beyond me especially on how to cater for multiplication and still be within the time and space complexity set out in the problem. Perhaps my entire approach is wrong? I'd appreciate some pointers and direction (not fully fleshed out answers) answers please.
Thanks
Notice that we only need to return the modulo 10 of xn.
We also need to know that if a = b + c, we have a % 10 = (b % 10 + c % 10) %10.
And a = b*c, so we also have a % 10 = (b %10 * c % 10) % 10;
So, for
xn = c(k-1) * x(n-1) + c(k-2) * x(n-2) + ... + c(0) * x(n-k)
= a0 + a1 + .... + an
(with a0 = c(k - 1)*x(n-1), a1 = ...)
we have xn % 10 = (a0 % 10 + a1 % 10 + ...)%10
And for each ai = ci*xi, so ai % 10 = (ci % 10 * xi % 10)% 10.
So by doing all of these math calculations, we can avoid to use double and keep the result in manageable size.
As Pham has answered, the trick is to realize that you only need to return a modulo, thereby bypassing the problem of overflow. Here is my quick attempt. I use a queue to put in the last result xN, and evict the oldest one.
static int solve(int[] coefficients, int[] seed, int n)
{
int k = coefficients.Count();
var queue = new Queue<int>(seed.Reverse().Take(k).Reverse());
for (int i = k; i <= n; i++)
{
var xn = coefficients.Zip(queue, (x, y) => x * y % 10).Sum() % 10;
queue.Enqueue(xn);
queue.Dequeue();
}
return (int) (queue.Last() );
}
Edit:
Getting the same results as you expect, however I don't guarantee that there is no bug in this example.

How can I compute a base 2 logarithm without using the built-in math functions in C#?

How can I compute a base 2 logarithm without using the built-in math functions in C#?
I use Math.Log and BigInteger.Log repeatedly in an application millions of times and it becomes painfully slow.
I am interested in alternatives that use binary manipulation to achieve the same. Please bear in mind that I can make do with Log approximations in case that helps speed up execution times.
Assuming you're only interested in the integral part of the logarithm, you can do something like that:
static int LogBase2(uint value)
{
int log = 31;
while (log >= 0)
{
uint mask = (1 << log);
if ((mask & value) != 0)
return (uint)log;
log--;
}
return -1;
}
(note that the return value for 0 is wrong; it should be negative infinity, but there is no such value for integral datatypes so I return -1 instead)
http://graphics.stanford.edu/~seander/bithacks.html
For the BigInteger you could use the toByteArray() method and then manually find the most significant 1 and count the number of zeroes afterward. This would give you the base-2 logarithm with integer precision.
The bit hacks page is useful for things like this.
Find the log base 2 of an integer with a lookup table
The code there is in C, but the basic idea will work in C# too.
If you can make due with approximations then use a trick that Intel chips use: precalculate the values into an array of suitable size and then reference that array. You can make the array start and end with any min/max values, and you can create as many in-between values as you need to achieve the desired accuracy.
You can try this C algorithm to get the binary logarithm (base 2) of a double N :
static double native_log_computation(const double n) {
// Basic logarithm computation.
static const double euler = 2.7182818284590452354 ;
unsigned a = 0, d;
double b, c, e, f;
if (n > 0) {
for (c = n < 1 ? 1 / n : n; (c /= euler) > 1; ++a);
c = 1 / (c * euler - 1), c = c + c + 1, f = c * c, b = 0;
for (d = 1, c /= 2; e = b, b += 1 / (d * c), b - e /* > 0.0000001 */ ;)
d += 2, c *= f;
} else b = (n == 0) / 0.;
return n < 1 ? -(a + b) : a + b;
}
static inline double native_ln(const double n) {
// Returns the natural logarithm (base e) of N.
return native_log_computation(n) ;
}
static inline double native_log_base(const double n, const double base) {
// Returns the logarithm (base b) of N.
// Right hand side can be precomputed to 2.
return native_log_computation(n) / native_log_computation(base) ;
}
Source

Categories