As an exercise, One of our student in apprenticeship is supposed to implement a recursive Sine function. (Using the generalized continued fraction)
I tried to help him, having done a fair share of coding in comparison, and am now stuck with a problem I don't understand.
I have a function that works.
What I don't understand is why my first three or four attempt failed.
I tried to debug this thing step-by-step but I can't pinpoint my error. I really would like to know what I'm missing.
Beware, for the code is not as beautiful as it could be. It's a quick and dirty proof of concept I wrote (many times) in 5 minutes.
Here's the code that doesn't work:
// number = the angle in radian
static double sinus(double number, double exp = 1, bool mustAdd = false, double precision = 0.000001)
{
if (number < 0) throw new ArgumentException("sinus");
if (number == 0) return 0;
double result = ((Math.Pow(number, exp)) / factorial(exp));
Console.WriteLine(result);
if (result > precision)
{
if (mustAdd)
return result += sinus(number, exp + 2, !mustAdd);
else
return result -= sinus(number, exp + 2, !mustAdd);
}
else
return result;
}
I'm printing every iteration with the intermediate values, in order to verify that everything is working accordingly. The values are correct.
Here's the working code I came up with (Yes it's dirty too):
static double Altersinus(double number, double exp = 1, bool mustAdd = true, double precision = 0.000001, double result = 0)
{
if (number < 0) throw new ArgumentException("altersinus");
if (number == 0) return 0;
double tmp = ((Math.Pow(number, exp)) / factorial(exp));
Console.WriteLine(tmp);
if (tmp > precision)
{
if (mustAdd)
result += tmp;
else
result -= tmp;
result = Altersinus(number, exp + 2, !mustAdd, precision, result);
}
return result;
}
I'm also writing the intermediate values, and they are exactly the same as the function that doesn't work.
Again, I'm really not searching for a solution, there is no rush. I'm merely trying to understand why it's not working. I would like to know what's technically different between my two methods.
Any idea would be much appreciated.
Cheers.
EDIT
I tried both function with the value 3.14159265358979 (roughly 180 degree)
Both function are printing theses intermediate values :
3.14159265358979
5.16771278004997
2.55016403987735
0.599264529320792
0.0821458866111282
0.00737043094571435
0.000466302805767612
2.19153534478302E-05
7.95205400147551E-07
The method that doesn't works returns -3.90268777359824 as a result, which is completely false.
The one that does works returns -7.72785889430639E-07. Which roughly corresponds to a zero.
I figured it out.
Let's replace the calculus by 'nx' where x is the exposant and n the number.
In the function that does work, I am effectively this:
Sine(n)=n1/1! - n3/3! + n5/5! - nx/x!...
But the one that doesn't work is slightly different. It's doing something else:
Sine(n)=n1/1! - (n3/3! + (n5/5! - (nx/x!...)))
The key here are the parenthesis.
It's affecting the calculus big time, because of the substraction.
If there was only addition it would not have caused any problem.
Related
I'm somewhat new to working with BigIntegers and have tried some stuff to get this system working, but feel a little stuck at the moment and would really appreciate a nudge in the right direction or a solution.
I'm currently working on a system which reduces BigInteger values down to a more readable form, and this is working fine with my current implementation, but I would like to further expand on it to get decimals implemented.
To better give a picture of what I'm attempting, I'll break it down.
In this context, we have a method which is taking a BigInteger, and returning it as a string:
public static string ShortenBigInt (BigInteger moneyValue)
With this in mind, when a number such as 10,000 is passed to this method, 10k will be returned. Same for 1,000,000 which will return 1M.
This is done by doing:
for(int i = 0; i < prefixes.Length; i++)
{
if(!(moneyValue >= BigInteger.Pow(10, 3*i)))
{
moneyValue = moneyValue / BigInteger.Pow(10, 3*(i-1));
return moneyValue + prefixes[i-1];
}
}
This system is working by grabbing a string from an array of prefixes and reducing numbers down to their simplest forms and combining the two and returning it when inside that prefix range.
So with that context, the question I have is:
How might I go about returning this in the same way, where passing 100,000 would return 100k, but also doing something like 1,111,111 would return 1.11M?
Currently, passing 1,111,111M returns 1M, but I would like that additional .11 tagged on. No more than 2 decimals.
My original thought was to convert the big integer into a string, then chunk out the first few characters into a new string and parse a decimal in there, but since prefixes don't change until values reach their 1000th mark, it's harder to tell when to place the decimal place.
My next thought was using BigInteger.Log to reduce the value down into a decimal friendly number and do a simple division to get the value in its decimal form, but doing this didn't seem to work with my implementation.
This system should work for the following prefixes, dynamically:
k, M, B, T, qd, Qn, sx, Sp,
O, N, de, Ud, DD, tdD, qdD, QnD,
sxD, SpD, OcD, NvD, Vgn, UVg, DVg,
TVg, qtV, QnV, SeV, SPG, OVG, NVG,
TGN, UTG, DTG, tsTG, qtTG, QnTG, ssTG,
SpTG, OcTG, NoTG, QdDR, uQDR, dQDR, tQDR,
qdQDR, QnQDR, sxQDR, SpQDR, OQDDr, NQDDr,
qQGNT, uQGNT, dQGNT, tQGNT, qdQGNT, QnQGNT,
sxQGNT, SpQGNT, OQQGNT, NQQGNT, SXGNTL
Would anyone happen to know how to do something like this? Any language is fine, C# is preferable, but I'm all good with translating. Thank you in advance!
formatting it manually could work a bit like this:
(prefixes as a string which is an char[])
public static string ShortenBigInt(BigInteger moneyValue)
{
string prefixes = " kMGTP";
double m2 = (double)moneyValue;
for (int i = 1; i < prefixes.Length; i++)
{
var step = Math.Pow(10, 3 * i);
if (m2 / step < 1000)
{
return String.Format("{0:F2}", (m2/step)) + prefixes[i];
}
}
return "err";
}
Although Falco's answer does work, it doesn't work for what was requested. This was the solution I was looking for and received some help from a friend on it. This solution will go until there are no more prefixes left in your string array of prefixes. If you do run out of bounds, the exception will be thrown and handled by returning "Infinity".
This solution is better due to the fact there is no crunch down to doubles/decimals within this process. This solution does not have a number cap, only limit is the amount of prefixes you make/provide.
public static string ShortenBigInt(BigInteger moneyValue)
{
if (moneyValue < 1000)
return "" + moneyValue;
try
{
string moneyAsString = moneyValue.ToString();
string prefix = prefixes[(moneyAsString.Length - 1) / 3];
BigInteger chopAmmount = (moneyAsString.Length - 1) % 3 + 1;
int insertPoint = (int)chopAmmount;
chopAmmount += 2;
moneyAsString = moneyAsString.Remove(Math.Min(moneyAsString.Length - 1, (int)chopAmmount));
moneyAsString = moneyAsString.Insert(insertPoint, ".");
return moneyAsString + " " + prefix;
}
catch (Exception exceptionToBeThrown)
{
return "Infinity";
}
}
This is a formula to approximate arcsine(x) using Taylor series from this blog
This is my implementation in C#, I don't know where is the wrong place, the code give wrong result when running:
When i = 0, the division will be 1/x. So I assign temp = 1/x at startup. For each iteration, I change "temp" after "i".
I use a continual loop until the two next value is very "near" together. When the delta of two next number is very small, I will return the value.
My test case:
Input is x =1, so excected arcsin(X) will be arcsin (1) = PI/2 = 1.57079633 rad.
class Arc{
static double abs(double x)
{
return x >= 0 ? x : -x;
}
static double pow(double mu, long n)
{
double kq = mu;
for(long i = 2; i<= n; i++)
{
kq *= mu;
}
return kq;
}
static long fact(long n)
{
long gt = 1;
for (long i = 2; i <= n; i++) {
gt *= i;
}
return gt;
}
#region arcsin
static double arcsinX(double x) {
int i = 0;
double temp = 0;
while (true)
{
//i++;
var iFactSquare = fact(i) * fact(i);
var tempNew = (double)fact(2 * i) / (pow(4, i) * iFactSquare * (2*i+1)) * pow(x, 2 * i + 1) ;
if (abs(tempNew - temp) < 0.00000001)
{
return tempNew;
}
temp = tempNew;
i++;
}
}
public static void Main(){
Console.WriteLine(arcsin());
Console.ReadLine();
}
}
In many series evaluations, it is often convenient to use the quotient between terms to update the term. The quotient here is
(2n)!*x^(2n+1) 4^(n-1)*((n-1)!)^2*(2n-1)
a[n]/a[n-1] = ------------------- * --------------------- -------
(4^n*(n!)^2*(2n+1)) (2n-2)!*x^(2n-1)
=(2n(2n-1)²x²)/(4n²(2n+1))
= ((2n-1)²x²)/(2n(2n+1))
Thus a loop to compute the series value is
sum = 1;
term = 1;
n=1;
while(1 != 1+term) {
term *= (n-0.5)*(n-0.5)*x*x/(n*(n+0.5));
sum += term;
n += 1;
}
return x*sum;
The convergence is only guaranteed for abs(x)<1, for the evaluation at x=1 you have to employ angle halving, which in general is a good idea to speed up convergence.
You are saving two different temp values (temp and tempNew) to check whether or not continuing computation is irrelevant. This is good, except that you are not saving the sum of these two values.
This is a summation. You need to add every new calculated value to the total. You are only keeping track of the most recently calculated value. You can only ever return the last calculated value of the series. So you will always get an extremely small number as your result. Turn this into a summation and the problem should go away.
NOTE: I've made this a community wiki answer because I was hardly the first person to think of this (just the first to put it down in a comment). If you feel that more needs to be added to make the answer complete, just edit it in!
The general suspicion is that this is down to Integer Overflow, namely one of your values (probably the return of fact() or iFactSquare()) is getting too big for the type you have chosen. It's going to negative because you are using signed types — when it gets to too large a positive number, it loops back into the negative.
Try tracking how large n gets during your calculation, and figure out how big a number it would give you if you ran that number through your fact, pow and iFactSquare functions. If it's bigger than the Maximum long value in 64-bit like we think (assuming you're using 64-bit, it'll be a lot smaller for 32-bit), then try using a double instead.
I'm trying to make it so that after every say 200 of a value, it will increase a global variable by 1. As you can see below the problem I have is that one, it isn't in any way shape or form efficient and really doesn't work well.
An overall of how I'd like this to work would be so that when GV.TotalNumberValue hits past a certain number, let's say 200, GV.TotalLevel will increase by one and update the text and this will happen every time that GV.TotalNumberValue increases by 200.
Finally, if this is going to be checking what the number is on constantly, should I have this bound to an event such as a button click or a timer? Your help's greatly appreciated, thanks.
void LevelMod()
{
if (GV.TotalNumberValue >= 200)
{
GV.TotalLevel = GV.TotalLevel + 1;
lblLevel.Text = string.Format("{0}{1}", GV.LevelPrefix, GV.TotalLevel);
}
else if (GV.TotalNumberValue >= 400)
{
GV.TotalLevel = GV.TotalLevel + 1;
lblLevel.Text = string.Format("{0}{1}", GV.LevelPrefix, GV.TotalLevel);
}
else
{
return;
}
}
Well, you can use simple math:
Either deduce the level from the value, like this:
int totalLevel = value / 200;
This works because an integer division is always rounded down.
Or, if you know that value has just been incremented, you can detect a level boundary like this:
bool shouldLevelUp = (value % 200) == 0;
if (shouldLevelUp)
++totalLevel;
Perhaps use integer division similar to:
void LevelMod()
{
// I assume the level variables are integrals, so perform an integer division
if (GV.TotalNumberValue / 200 > GV.TotalLevel)
{
GV.TotalLevel = GV.TotalNumberValue / 200;
lblLevel.Text = string.Format("{0}{1}", GV.LevelPrefix, GV.TotalLevel);
}
}
Essentially, your TotalLevel is always TotalNumberValue / 200. This assumes that that GV.TotalNumberValue is an integral type which always rounds the result towards zero.
I'm having a problem generating the Terras number sequence.
Here is my unsuccessful attempt:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Terras
{
class Program
{
public static int Terras(int n)
{
if (n <= 1)
{
int return_value = 1;
Console.WriteLine("Terras generated : " + return_value);
return return_value;
}
else
{
if ((n % 2) == 0)
{
// Even number
int return_value = 1 / 2 * Terras(n - 1);
Console.WriteLine("Terras generated : " + return_value);
return return_value;
}
else
{
// Odd number
int return_value = 1 / 2 * (3 * Terras(n - 1) + 1);
Console.WriteLine("Terras generated : " + return_value);
return return_value;
}
}
}
static void Main(string[] args)
{
Console.WriteLine("TERRAS1");
Terras(1); // should generate 1
Console.WriteLine("TERRAS2");
Terras(2); // should generate 2 1 ... instead of 1 and 0
Console.WriteLine("TERRAS5");
Terras(5); // should generate 5,8,4,2,1 not 1 0 0 0 0
Console.Read();
}
}
}
What am I doing wrong?
I know the basics of recursion, but I don’t understand why this doesn’t work.
I observe that the first number of the sequence is actually the number that you pass in, and subsequent numbers are zero.
Change 1 / 2 * Terros(n - 1); to Terros(n - 1)/2;
Also 1 / 2 * (3 * Terros(n - 1) + 1); to (3 * Terros(n - 1) + 1)/2;
1/2 * ... is simply 0 * ... with int math.
[Edit]
Recursion is wrong and formula is mis-guided. Simple iterate
public static void Terros(int n) {
Console.Write("Terros generated :");
int t = n;
Console.Write(" " + t);
while (t > 1) {
int t_previous = t;
if (t_previous%2 == 0) {
t = t_previous/2;
}
else {
t = (3*t_previous+1)/2;
}
Console.Write(", " + t);
}
Console.WriteLine("");
}
The "n is even" should be "t(subscript n-1) is even" - same for "n is odd".
int return_value = 1 / 2 * Terros(n - 1);
int return_value = 1 / 2 * (3 * Terros(n - 1) + 1);
Unfortunately you've hit a common mistake people make with ints.
(int)1 / (int)2 will always be 0.
Since 1/2 is an integer divison it's always 0; in order to correct the math, just
swap the terms: not 1/2*n but n/2; instead of 1/2* (3 * n + 1) put (3 * n + 1) / 2.
Another issue: do not put computation (Terros) and output (Console.WriteLine) in the
same function
public static String TerrosSequence(int n) {
StringBuilder Sb = new StringBuilder();
// Again: dynamic programming is far better here than recursion
while (n > 1) {
if (Sb.Length > 0)
Sb.Append(",");
Sb.Append(n);
n = (n % 2 == 0) ? n / 2 : (3 * n + 1) / 2;
}
if (Sb.Length > 0)
Sb.Append(",");
Sb.Append(n);
return Sb.ToString();
}
// Output: "Terros generated : 5,8,4,2,1"
Console.WriteLine("Terros generated : " + TerrosSequence(5));
The existing answers guide you in the correct direction, but there is no ultimate one. I thought that summing up and adding detail would help you and future visitors.
The problem name
The original name of this question was “Conjuncture of Terros”. First, it is conjecture, second, the modification to the original Collatz sequence you used comes from Riho Terras* (not Terros!) who proved the Terras Theorem saying that for almost all t₀ holds that ∃n ∈ ℕ: tₙ < t₀. You can read more about it on MathWorld and chux’s question on Math.SE.
* While searching for who is that R. Terras mentioned on MathWorld, I found not only the record on Geni.com, but also probable author of that record, his niece Astrid Terras, and her family’s genealogy. Just for the really curious ones. ☺
The formula
You got the formula wrong in your question. As the table of sequences for different t₀ shows, you should be testing for parity of tₙ₋₁ instead of n.
Formula taken from MathWorld.
Also the second table column heading is wrong, it should read t₀, t₁, t₂, … as t₀ is listed too.
You repeat the mistake with testing n instead of tₙ₋₁ in your code, too. If output of your program is precisely specified (e.g. when checked by an automatic judge), think once more whether you should output t₀ or not.
Integer vs float arithmetic
When making an operation with two integers, you get an integer. If a float is involved, the result is float. In both branches of your condition, you compute an expression of this form:
1 / 2 * …
1 and 2 are integers, therefore the division is integer division. Integer division always rounds down, so the expression is in fact
0 * …
which is (almost*) always zero. Mystery solved. But how to fix it?
Instead of multiplying by one half, you can divide by two. In even branch, division by 2 gives no remainder. In odd branch, tₙ₋₁ is odd, so 3 · tₙ₋₁ is odd too. Odd plus 1 is even, so division by two always produces remainder equal to zero in both branches. Integer division is enough, the result is precise.
Also, you could use float division, just replace 1 with 1.0. But this will probably not give correct results. You see, all members of the sequence are integers and you’re getting float results! So rounding with Math.Round() and casting to integer? Nah… If you can, always evade using floats. There are very few use cases for them, I think, most having something to do with graphics or numerical algorithms. Most of the time you don’t really need them and they just introduce round-off errors.
* Zero times whatever could produce NaN too, but let’s ignore the possibility of “whatever” being from special float values. I’m just pedantic.
Recursive solution
Apart from the problems mentioned above, your whole recursive approach is flawed. Obviously you intended Terras(n) to be tₙ. That’s not utterly bad. But then you forgot that you supply t₀ and search for n instead of the other way round.
To fix your approach, you would need to set up a “global” variable int t0 that would be set to given t₀ and returned from Terras(0). Then Terras(n) would really return tₙ. But you wouldn’t still know the value of n when the sequence stops. You could only repeat for bigger and bigger n, ruining time complexity.
Wait. What about caching the results of intermediate Terras() calls in an ArrayList<int> t? t[i] will contain result for Terras(i) or zero if not initialized. At the top of Terras() you would add if (n < t.Count() && t[n] != 0) return t[n]; for returning the value immediately if cached and not repeating the computation. Otherwise the computation is really made and just before returning, the result is cached:
if (n < t.Count()) {
t[n] = return_value;
} else {
for (int i = t.Count(); i < n; i++) {
t.Add(0);
}
t.Add(return_value);
}
Still not good enough. Time complexity saved, but having the ArrayList increases space complexity. Try tracing (preferably manually, pencil & paper) the computation for t0 = 3; t.Add(t0);. You don’t know the final n beforehand, so you must go from 1 up, till Terras(n) returns 1.
Noticed anything? First, each time you increment n and make a new Terras() call, you add the computed value at the end of cache (t). Second, you’re always looking just one item back. You’re computing the whole sequence from the bottom up and you don’t need that big stupid ArrayList but always just its last item!
Iterative solution
OK, let’s forget that complicated recursive solution trying to follow the top-down definition and move to the bottom-up approach that popped up from gradual improvement of the original solution. Recursion is not needed anymore, it just clutters the whole thing and slows it down.
End of sequence is still found by incrementing n and computing tₙ, halting when tₙ = 1. Variable t stores tₙ, t_previous stores previous tₙ (now tₙ₋₁). The rest should be obvious.
public static void Terras(int t) {
Console.Write("Terras generated:");
Console.Write(" " + t);
while (t > 1) {
int t_previous = t;
if (t_previous % 2 == 0) {
t = t_previous / 2;
} else {
t = (3 * t_previous + 1) / 2;
}
Console.Write(", " + t);
}
Console.WriteLine("");
}
Variable names taken from chux’s answer, just for the sake of comparability.
This can be deemed a primitive instance of dynamic-programming technique. The evolution of this solution is common to the whole class of such problems. Slow recursion, call result caching, dynamic “bottom-up” approach. When you are more experienced with dynamic programming, you’ll start seeing it directly even in more complicated problems, not even thinking about recursion.
I'm solving Project Euler problems for kicks, I'm currently at number 10.
First of all: I know there are other solutions, I'm currently writing another method using the sieve of Eratosthenes. What I'd like your help with is understanding why this code does not work.
This is my code (the problems involves finding the sum of every prime under 2 million). The prime-checking method seems to work fine, but the result is way less than it should be.
class Euler10
{
public static void Main()
{
long sum = 0; // Was originally an int. Thanks Soner Gönül!
for(int i = 1; i < 2000000; i++)
{
if (CheckIfPrime(i) == true)
sum += i;
}
System.Console.WriteLine(sum);
System.Console.Read();
}
static bool CheckIfPrime(int number)
{
if (number <= 1)
return false;
if (number == 2)
return true;
if (number % 2 == 0)
return false;
for (int i = 3; i*i < number; i += 2)
{
if ((number % i) == 0)
return false;
}
return true;
}
}
The number I get is 1,308,111,344, which is two orders of magnitude lower than it should be. The code is so simple I am baffled by this error.
EDIT: making sum a long solved the digit problem, thanks everyone! Now, though, I get 143042032112 as an answer: the i*i in CheckIfPrime() isn't always right.
Using the sqrt() function and adding one (to compensate for the int cast) gives the correct result. Here's the correct CheckIfPrime() function:
bool CheckIfPrime(int number)
{
if (number <= 1)
return false;
if (number == 2)
return true;
if (number % 2 == 0)
return false;
int max = 1 + (int)System.Math.Sqrt(number);
for (int i = 3; i < max; i += 2)
{
if ((number % i) == 0)
return false;
}
return true;
}
EDIT 2: Will Ness helped me optimize the code further (calculating number's square root and comparing it to i is slower than elevating i^2 and then comparing it to number): the problem with the original method is that it didn't take into consideration edge cases in which number is the exact square of i, thus sometimes returning true instead of false. The correct code for CheckIfPrime(), then, is:
bool CheckIfPrime(int number)
{
if (number <= 1)
return false;
if (number == 2)
return true;
if (number % 2 == 0)
return false;
for (int i = 3; i*i <= number; i += 2)
{
if ((number % i) == 0)
return false;
}
return true;
}
Thanks again people!
Your code does not work because it tries using a 32-bit int to hold a number that exceeds the highest value in a 32-bit variable. The answer to the problem is 142,913,828,922, which needs 38 bits.
Changing the data type of sum to long should fix this problem.
Using long should help.http://msdn.microsoft.com/en-us/library/ctetwysk.aspx
Gives you a 64 bit integer where as int is only 32 bits.
You are using int for sum variable which is 32-bit but you are try to assign it more than Int32.Maximum which is 2,147,483,647.
But your result is 143,042,032,112 which needs more bits than 32 for storing it.
Set its type as long which stores 64 bit.
long sum = 0;
Here a working DEMO.
for (... i=3 ; i*i < number; i+=2 ) is wrong. It should be
for (... i=3 ; i*i <= number; i+=2 )
...
both i and number must be of the same type of course; this will almost never give you an overflow, since you start from 3 (unless number is very big, close to the upper limit of the type's range).
The comparison should be inclusive to catch cases where number is a square of a prime.
Your algorithm is not the Sieve of Eratosthenes; the modulo operator gives it away. Your algorithm is trial division by odd numbers. Here is a function using the Sieve of Eratosthenes:
function sumPrimes(n)
sum := 0
sieve := makeArray(2..n, True)
for p from 2 to n step 1
if sieve[p]
sum := sum + p
for i from p * p to n step p
sieve[i] := False
return sum
Calling sumPrimes(2000000) gives the answer, which I won't write down out of respect for Project Euler. That function runs in time O(n log log n), which is much better than the O(n^2) of your original program. There are better ways to sieve, but that is simple, and easy to get right, and good enough for most purposes, including yours. You should get an answer in less than a second.
I'll leave it to you to translate to C# with appropriate data types.
If you're interested in a somewhat larger version of this problem, I calculated the sum of the first billion primes at my blog: 11138479445180240497.