Why is this Fibonacci code not correct? [closed] - c#

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Project Euler Question 2.
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
My solution :
int firstNum = 1;
int secondNum = 2;
int resultNum = firstNum + secondNum;
int sum = 0;
for (int i = 0; i < 4000000; i++)
{
firstNum = i;
secondNum = i;
if(resultNum == firstNum + secondNum)
{
sum += resultNum;
Console.WriteLine(sum);
}
}
Why is this not correct and can you guide me into the right way of thinking?

Try this:
int n1, n2, fib;
//n1 = 0;
//n2 = 1;
n1 = 1;
n2 = 1;
fib = n1 + n2;
while (fib < 4000000)
{
n2 = n1;
n1 = fib;
fib = n1 + n2;
}
Then find the even fib numbers and sum it

For a more modular approach (mixed with LINQ):
IEnumerable<Int32> Fibonacci(Int32 limit = 4000000)
{
for (Int32 previous = 0, current = 1, next = 0;
current <= limit; current = next)
{
next = previous + current;
previous = current;
yield return next;
}
}
Then:
var allNumbers = Fibonacci(4000000); // 1,2,3,5,8,13,21
var evenNumbers = allNumbers.Where(x => x % 2 == 0); // 2,8,34,144,610,2584
var sum = evenNumbers.Sum(); // 4613732

The fibonacci series is defined as
A0 = 1,
A1 = 1
An = An-1 + An-2
You are aiming at producing the pattern
1 2 3 5 8 13 etc
While iterating, you are going to want to adjust the input similar to a sliding window and then check to see if you have come across a valid insertion (i.e. < 4M and even)
int sum = 0;
int max = 4000000;
for( int n = 0; n < max ; n++ )
{
//only sum the even numbers
if( second % 2 == 0 ) sum += second;
//adjust
int result = first + second;
first = second;
second = result;
//test for numbers greater than max
if( result > max ) break;
}
//output
Console.WriteLine(sum); //An for all even An values
After looking at this hopefully you can see some of the issues you came across.
You are setting your variables to the iterator i which is not going to produce An as defined but instead something entirely different.
firstNum = i;
secondNum = i;
Further, you only calculate the result once. This needs to be done in the loop. Only calculating once will basically use a static value the entire time.
int resultNum = firstNum + secondNum;
The conditional statement should be testing for an even number in order to properly add to the sum, but this code will only test the static value of resultNum
if(resultNum == firstNum + secondNum)
Also, there needs to be some check on the sum in order to break out when the max is exceeded. 4M iterations will be too many.
There is even more optimization that can occur here though. Looking at the for loop, it is clear that while not used yet, the iterator can be a powerful tool.
The reason being that the fibonacci conforms to the "Golden ratio".
By making the simple observation that the fibonacci series hits an even number ever 3 iterations, the iterator can be used to skip through the series.
double p = (1 + Math.Pow(5,.5)) / 2;
for( int n = 3, sum = 0;;n+=3)
{
double f = ( Math.Pow(p,n) - Math.Pow( 1 - p , n ) ) / Math.Pow(5,.5);
if( f > 4000000 ){
Console.WriteLine(sum);
break;
}
sum += (int)Math.Round(f);
}

Your code does not produce a Fibonacci sequence and does no check for even-valued terms
Try this instead
int firstNum = 1;
int secondNum = 2;
int sum = 0;
while (secondNum <= 4000000)
{
if (secondNum % 2 == 0)
sum += secondNum;
int resultNum = firstNum + secondNum;
firstNum = secondNum;
secondNum = resultNum;
}
Console.WriteLine(sum);

Related

How can I calculate numbers (for example) from 1 - 10 with the next number. (1+2+3+4+ ...) [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
Does it have a shorter way than doing something like this:
int[] Summe = new int[6];
Summe[0] = 1;
Summe[1] = 2;
Summe[2] = 3;
Summe[3] = 4;
Summe[4] = 5;
Summe[5] = 6;
Console.WriteLine(Summe[0] + Summe[1] + Summe[2] + Summe[3] + Summe[4] + Summe[5]);
Console.ReadKey();
Using the Enumerable.Sum() method which computes the sum of a sequence of numeric values and Enumerable.Take() which returns a specified number of contiguous elements from the start of a sequence.
Console.WriteLine(Summe.Take(10).Sum());
OR from high school
// sum of integers from 1 to n
int SumNaturalNumbers(int n)
{
return n * (n + 1) / 2;
}
Formula for the general algebraic series starting from a and difference between terms d (Arithmetic progression and series)
sum = n / 2 * (2 * a + (n - 1) * d)
I think using a foreach loop may be helpful here, since you're dealing with an array. Also, you can define your array on one line.
int[] Summe = { 1, 2, 3, 4, 5, 6 };
int total = 0;
foreach (int number in Summe)
{
total += number;
}
Console.WriteLine(total);
Console.ReadKey();
You can simplify this process by simply putting this operation into a while loop.
int i = 0; // tell your program what 'i' should be upon first running the code
while (i < 10) // if 'i' is less than 10, run this block of code. You can change 10 to anything you want
{
Console.WriteLine("i = {0}", i);
i++; // increment
}
This will print each number individually, but you want to calculate the sum of every number, so you could do something like this:
{
public static void Main()
{
int j, sum = 0;
Console.Write("\n\n");
Console.Write("Find the sum of first 10 natural numbers:\n");
Console.Write("----------------------------------------------");
Console.Write("\n\n");
Console.Write("The first 10 natural number are :\n");
for (j = 1; j <= 10; j++)
{
sum = sum + j; // add the previous number to the current one
Console.Write("{0} ",j);
}
Console.Write("\nThe Sum is : {0}\n", sum);
}
}
The above code prints the sum of the first 10 natural numbers. I added some additional lines simply to make the program more legible. Again, you can change the number 10 to whatever number you want.

'Summation of primes' takes too long [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I don't know why this takes forever for big numbers I'm trying to solve Problem 10 in Project Euler (https://projecteuler.net/problem=10). Can someone help me please?
It finds the first prime number and crosses all its factors, Then moves on to the next prime number and so on.
long sum=0;
int howmanyChecked = 1;
int target = 1000000;
int index = -1;
List<int> numbers = new List<int>(target);
List<bool> Isprime = new List<bool>(target);
for(int i=2;i<=target;i++)
{
numbers.Add(i);
Isprime.Add(true);
}
while (1 > 0)
{
index = Isprime.IndexOf(true, index + 1);
int Selected = numbers[index];
howmanyChecked++;
sum += Selected;
//Console.WriteLine($"selected prime number is {Selected}");
//int startfrom =numbers.IndexOf(Selected * Selected);
if (Selected >= target / 2)
{
Console.WriteLine("ss");
for(int i=index+1;i<target-1;i++)
{
if(Isprime[i]==true)
{
Console.WriteLine(numbers[i].ToString());
sum += numbers[i];
}
}
Console.WriteLine($"the sum of all prime nubers below {target} is {sum} tap to continue");
Console.ReadLine();
break;
}
else
{
for (int i = Selected; i * Selected <= target; i++)
{
int k = numbers.IndexOf(i * Selected);
if (k == -1)
break;
if (Isprime[k] == true)
{
Isprime[numbers.IndexOf(i * Selected)] = false;
howmanyChecked++;
//Console.WriteLine($"Checked number is {Selected * i} and we have counted {howmanyChecked} numbers");
}
}
}
if (howmanyChecked == target || index==target)
break;
}
Console.ReadLine();
Apply some straightforward optimizations:
list numbers should not be used because each number can be calculated based on an index
simplified initialization of Isprime.
For 1'000'000 got:
the sum of all prime numbers below 1000000 is 37548466742 tap to continue
long sum = 0;
int howmanyChecked = 1;
int target = 1000000;
int index = -1;
var Isprime = Enumerable.Repeat(true, target).ToArray();
while (1 > 0)
{
index = Array.IndexOf(Isprime, true, index + 1);
int Selected = index + 2;
howmanyChecked++;
sum += Selected;
//Console.WriteLine($"selected prime number is {Selected}");
//int startfrom =numbers.IndexOf(Selected * Selected);
if (Selected >= target / 2)
{
Console.WriteLine("ss");
for (int i = index + 1; i < target - 1; i++)
{
if (Isprime[i] == true)
{
Console.WriteLine(i + 2);
sum += i + 2;
}
}
Console.WriteLine($"the sum of all prime nubers below {target} is {sum} tap to continue");
Console.ReadLine();
break;
}
else
{
for (int i = Selected; i * Selected <= target; i++)
{
int k = i * Selected - 2;
if (k < 0)
break;
if (Isprime[k] == true)
{
Isprime[k] = false;
howmanyChecked++;
//Console.WriteLine($"Checked number is {Selected * i} and we have counted {howmanyChecked} numbers");
}
}
}
if (howmanyChecked == target || index == target)
break;
}
Console.ReadLine();
Do SoE (Sieve of Eratosthenes) up to n=2000000 in case you want to be memory efficient 2000000/16 = 62500 Bytes as you need just one bit per odd number). You can do the sum while filling SoE.
Your description is a SoE but you got too much code for a SoE ... my simple SoE solution for this is just 11 lines of formatted C++ code where half of it is variables declaration:
const DWORD N=2000000; // ~ 36 ms
const DWORD M=N>>1; // store only odd values from 3,5,7,...
char p[M]; // p[i] -> is 1+i+i prime? (factors map)
DWORD i,j,k,ss=0,n=0x10000000-N;
uint<2> s=2;
p[0]=0; for (i=1;i<M;i++) p[i]=1;
for(i=3,j=i>>1;i<N;i+=2,j++)
{
if (p[j]==1) { ss+=i; if (ss>=n) { s+=DWORD(ss); ss=0; }}
for(k=i+j;k<M;k+=i) p[k]=0;
} s+=DWORD(ss);
// s holds the answer 142913828922
where DWORD is unsigned 32bit int and uint<2> is 64bit unsigned int (as I am still on 32bit compiler that is why I do the sum so weirdly). As you can see you got maybe 3 times more code than necessary.
Using IsPrime without memoization is too slow but even with memoization can never beat SoE. see:
Prime numbers by Eratosthenes quicker sequential than concurrently?
btw. I got my Euler projects in single app where I do SoE up to 10^7 which creates a list of all primes up to 10^7 this takes 130 ms on my pretty old PC and that is then used for all the Euler problems related to primes (which speeds them up so the first 40 problems is finished below 1sec) which for this case (different solution code) takes 0.7 ms.
To avoid overflows sum on 64 bit arithmetics.
Also using dynamic lists without pre-allocation is slow. You do not need them anyway.
Try with this:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
int main()
{
int n,i,i1,imax;
long sumprime;
bool *prime5mod6,*prime1mod6;
n=2000000;
imax=(n-n%6)/6+1;
prime5mod6 = (bool *) calloc(imax+1,sizeof(bool));
prime1mod6 = (bool *) calloc(imax+1,sizeof(bool));
sumprime=5;
for(i=1;(6*i-1)*(6*i-1)<=n;i++){
if(prime5mod6[i]==false){
sumprime=sumprime+6*i-1;
for(i1=6*i*i;i1 <= imax+2*i;i1+=(6*i-1)){
if(i1<=imax)
prime5mod6[i1]=true;
prime1mod6[i1-2*i]=true;
}
}
if(prime1mod6[i]==false){
sumprime=sumprime+6*i+1;
for(i1 = 6*i*i;i1<=imax;i1+=(6*i+1)){
prime5mod6[i1]=true;
if(i1<=imax-2*i)
prime1mod6[i1+2*i]=true;
}
}
}
for(i1=i;i1<=imax-1;i1++){
if(prime5mod6[i1]==false)
sumprime=sumprime+6*i1-1;
if(prime1mod6[i1]==false)
sumprime=sumprime+6*i1+1;
}
if(prime5mod6[imax]==false && n%6==5)
sumprime=sumprime+6*imax-1;
if(prime1mod6[imax-1]==false && n%6==0)
sumprime=sumprime-(6*(imax-1)+1);
printf("\nPrime sum: %ld",sumprime);
free(prime5mod6);
free(prime1mod6);
return 0;
}

Find furthest and closest number to a number in array c# [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have a exercise where I need to find the furthest and closest number to a certain number (average). Can somebody help me? Here is my code:
Console.WriteLine("Geef 10 gehele positieve getallen.");
Console.WriteLine("Getal 1:");
int g1 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Getal 2:");
int g2 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Getal 3:");
int g3 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Getal 4:");
int g4 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Getal 5:");
int g5 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Getal 6:");
int g6 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Getal 7:");
int g7 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Getal 8:");
int g8 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Getal 9:");
int g9 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Getal 10:");
int g10 = Convert.ToInt32(Console.ReadLine());
int gemiddelde = (g1 + g2 + g3 + g4 + g5 + g6 + g7 + g8 + g9 + g10)/10;
int[] array = new int[10] {g1,g2,g3,g4,g5,g6,g7,g8,g9,g10};
If you can use List<int> instead of array it makes things easier to code and probably cleaner depending on who you ask.
let say you change this :
int[] array = new int[10] {g1,g2,g3,g4,g5,g6,g7,g8,g9,g10};
Into a list like this :
List<int> values = new List<int>(){g1,g2,g3,g4,g5,g6,g7,g8,g9,g10};
An aggregate will test each elements until the list has been completely tested.
So we can try get the closest and furthest value like so
// value you want to check is the average of the list.
// Average is already implemented for the List
var value = values.Average();
// will keep the closest value in the collection to our value we are looking for
// and keep testing with the following value to end up with the final closest
var closestTo = values.Aggregate((x, y) => Math.Abs(x - value) < Math.Abs(y - value) ? x : y);
// same logic as closest except we keep the furthest
var furthestTo = values.Aggregate((x, y) => Math.Abs(x - value) > Math.Abs(y - value) ? x : y);
I hope this example can help you even if it is in java.
//Your array with the numbers
int[] data = {12, 123, 65, 23, 4, 213, 32, 342, 21, 15};
int testNum = 27; //Your test value
int holderHigh = testNum;
for(int i = 0; i < data.length; i++){//Goes through the array
//If the holder is lower than a value in the array it will get stored
if(holderHigh < data[i]){
holderHigh = data[i];
}
}
int holderLow = testNum;
for(int k = 0; k < data.length; k++){//Goes through the array
//If the holder is higher than a value in the array it will get stored
if(holderLow > data[k]){
holderLow = data[k];
}
}
System.out.println(holderHigh + " and " + holderLow +
" is the number farthest away from " + testNum);stNum);

Get sum of each digit below n as long

This is the code I have but it's to slow, any way to do it faster..
the number range I'm hitting is 123456789 but I can't get it below 15 seconds, and I need it to get below 5 seconds..
long num = 0;
for (long i = 0; i <= n; i++)
{
num = num + GetSumOfDigits(i);
}
static long GetSumOfDigits(long n)
{
long num2 = 0;
long num3 = n;
long r = 0;
while (num3 != 0)
{
r = num3 % 10;
num3 = num3 / 10;
num2 = num2 + r;
}
return num2;
}
sum =(n(n+1))/2 is not giving me the results I need, not calculating properly..
For N = 12 the sum is 1+2+3+4+5+6+7+8+9+(1+0)+(1+1)+(1+2)= 51.
I need to do this with a formula instead of a loop..
I've got about 15 tests to run through each under 6 seconds..
with parallel I got one test from 15seconds to 4-8 seconds..
Just to show you the test I'm doing this is the hard one..
[Test]
public void When123456789_Then4366712385()
{
Assert.AreEqual(4366712385, TwistedSum.Solution(123456789));
}
On my computer I can run all the tests under 5 seconds..
Look at the photo..
With DineMartine Answer I got these results:
Your algorithm complexity is N log(N). I have found a better algorithm with complexity log(N). The idea is to iterate on the number of digits which is :
log10(n) = ln(n)/ln(10) = O(log(n)).
The demonstration of this algorithm involves a lot of combinatorial calculus. So I choose not to write it here.
Here is the code :
public static long Resolve(long input)
{
var n = (long)Math.Log10(input);
var tenPow = (long)Math.Pow(10, n);
var rest = input;
var result = 0L;
for (; n > 0; n--)
{
var dn = rest / tenPow;
rest = rest - dn * tenPow;
tenPow = tenPow / 10;
result += dn * (rest + 1) + dn * 45 * n * tenPow + dn * (dn-1) * tenPow * 5 ;
}
result += rest * (rest + 1) / 2;
return result;
}
Now you would solve the problem in a fraction of second.
The idea is to write the input as a list of digit :
Assuming the solution is given by a function f, we are looking for g a recursive expression of f over n :
Actually g can be written as follow :
If you find h, the problem would be practically solved.
A little bit convoluted but gets the time down to practicaly zero:
private static long getSumOfSumOfDigitsBelow(long num)
{
if (num == 0)
return 0;
// 1 -> 1 ; 12 -> 10; 123 -> 100; 321 -> 100, ...
int pow10 = (int)Math.Pow(10, Math.Floor(Math.Log10(num)));
long firstDigit = num / pow10;
long sum = 0;
var sum999 = getSumOfSumOfDigitsBelow(pow10 - 1);
var sumRest = getSumOfSumOfDigitsBelow(num % pow10);
sum += (firstDigit - 1)*(firstDigit - 0)/2*pow10 + firstDigit*sum999;
sum += firstDigit*(num%pow10 + 1) + sumRest;
return sum;
}
getSumOfSumOfDigitsBelow(123456789) -> 4366712385 (80us)
getSumOfSumOfDigitsBelow(9223372036854775807) -> 6885105964130132360 (500us - unverified)
The trick is to avoid to compute the same answer again and again. e.g. 33:
your approach:
sum = 1+2+3+4+5+6+7+8+9+(1+0)+(1+1)+(1+2)+ ... +(3+2)+(3+3)
my approach:
sum = 10*(0 + (1+2+3+4+5+6+7+8+9)) +
10*(1 + (1+2+3+4+5+6+7+8+9)) +
10*(2 + (1+2+3+4+5+6+7+8+9)) +
3*(3 + (1 + 2 + 3))
The (1+2+3+4+5+6+7+8+9)-part have to be calculated only once. The loop of 0..firstDigit-1 can be avoided by the n(n-1)/2-trick. I hope this makes sense.
The complexity is O(2^N) with N counting the number of digits. This looks very bad but is fast enough for your threshold of 5s even for long-max. It may be possible to transform this algorithm in something running in O(n) by calling getSumOfSumOfDigitsBelow() only once but it would look much more complex.
First step of optimization: look at your algorithm ;)
Comming back to this problem after the answer of DineMartine :
To further optimize the algorithm, the sum999-part can be replaced by an explicit formula. Lets take some number 9999...9=10^k-1 into the code and replace accordingly:
sum(10^k-1) = (9 - 1)*(9 - 0)/2*pow10 + 9*sum999 + 9*(num%pow10 + 1) + sumRest
sum(10^k-1) = 36*pow10 + 9*sum999 + 9*(num%pow10 + 1) + sumRest
sum999 and sumRest are the same for the numbers of type 10^k:
sum(10^k-1) = 36*pow10 + 10*sum(10^(k-1)-1) + 9*(num%pow10 + 1)
sum(10^k-1) = 36*pow10 + 10*sum(10^(k-1)-1) + 9*((10^k-1)%pow10 + 1)
sum(10^k-1) = 36*pow10 + 10*sum(10^(k-1)-1) + 9*pow10
sum(10^k-1) = 45*pow10 + 10*sum(10^(k-1)-1)
We have a definition of sum(10^k-1) and know sum(9)=45. And we get:
sum(10^k-1) = 45*k*10^k
The updated code:
private static long getSumOfSumOfDigitsBelow(long num)
{
if (num == 0)
return 0;
long N = (int) Math.Floor(Math.Log10(num));
int pow10 = (int)Math.Pow(10, N);
long firstDigit = num / pow10;
long sum = (firstDigit - 1)*firstDigit/2*pow10
+ firstDigit* 45 * N * pow10 / 10
+ firstDigit*(num%pow10 + 1)
+ getSumOfSumOfDigitsBelow(num % pow10);
return sum;
}
This is the same algorithm as the one from DineMartine but expressed in a recursive fashion (I've compared both implementations and yes I'm sure it is ;) ). The runtime goes down to practically zero and the time complexity is O(N) counting the number of digits or O(long(N)) taking the value.
If you have multiple processors (or cores) in your system, you can speed it up quite a lot by doing the calculations in parallel.
The following code demonstrates (it's a compilable console app).
The output when I try it on my system (4 cores with hyperthreading) is as follows for a release build:
x86 version:
Serial took: 00:00:14.6890714
Parallel took: 00:00:03.5324480
Linq took: 00:00:04.4480217
Fast Parallel took: 00:00:01.6371894
x64 version:
Serial took: 00:00:05.1424354
Parallel took: 00:00:00.9860272
Linq took: 00:00:02.6912356
Fast Parallel took: 00:00:00.4154711
Note that the parallel version is around 4 times faster. Also note that the x64 version is MUCH faster (due to the use of long in the calculations).
The code uses Parallel.ForEach along with a Partitioner to split the range of number into sensible regions for the number of processors available. It also uses Interlocked.Add() to quickly add the numbers with efficient locking.
I've also added another method where you need to pre-calculate the sums for the numbers between 0 and 1000. You should only need to pre-calculate the sums once for each run of the program. See FastGetSumOfDigits().
Using FastGetSumOfDigits() more than doubles the previous fastest time on my PC. You can increase the value of SUMS_SIZE to a larger multiple of 10 to increase the speed still further, at the expense of space. Increasing it to 10000 on my PC decreased the time to ~0.3s
(The sums array only needs to be a short array, to save space. It doesn't need a larger type.)
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
internal class Program
{
public static void Main()
{
long n = 123456789;
Stopwatch sw = Stopwatch.StartNew();
long num = 0;
for (long i = 0; i <= n; i++)
num = num + GetSumOfDigits(i);
Console.WriteLine("Serial took: " + sw.Elapsed);
Console.WriteLine(num);
sw.Restart();
num = 0;
var rangePartitioner = Partitioner.Create(0, n + 1);
Parallel.ForEach(rangePartitioner, (range, loopState) =>
{
long subtotal = 0;
for (long i = range.Item1; i < range.Item2; i++)
subtotal += GetSumOfDigits(i);
Interlocked.Add(ref num, subtotal);
});
Console.WriteLine("Parallel took: " + sw.Elapsed);
Console.WriteLine(num);
sw.Restart();
num = Enumerable.Range(1, 123456789).AsParallel().Select(i => GetSumOfDigits(i)).Sum();
Console.WriteLine("Linq took: " + sw.Elapsed);
Console.WriteLine(num);
sw.Restart();
initSums();
num = 0;
Parallel.ForEach(rangePartitioner, (range, loopState) =>
{
long subtotal = 0;
for (long i = range.Item1; i < range.Item2; i++)
subtotal += FastGetSumOfDigits(i);
Interlocked.Add(ref num, subtotal);
});
Console.WriteLine("Fast Parallel took: " + sw.Elapsed);
Console.WriteLine(num);
}
private static void initSums()
{
for (int i = 0; i < SUMS_SIZE; ++i)
sums[i] = (short)GetSumOfDigits(i);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long GetSumOfDigits(long n)
{
long sum = 0;
while (n != 0)
{
sum += n%10;
n /= 10;
}
return sum;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long FastGetSumOfDigits(long n)
{
long sum = 0;
while (n != 0)
{
sum += sums[n % SUMS_SIZE];
n /= SUMS_SIZE;
}
return sum;
}
static short[] sums = new short[SUMS_SIZE];
private const int SUMS_SIZE = 1000;
}
}
To increase performance you could calculate the sum starting from the highest number.
Let r=n%10 + 1. Calculate the sum for the last r numbers.
Then we note that if n ends with a 9, then the total sum can be calculated as 10 * sum(n/10) + (n+1)/10 * 45. The first term is the sum of all digits but the last, and the second term is the sum of the last digit.
The function to calculate the total sum becomes:
static long GetSumDigitFrom1toN(long n)
{
long num2 = 0;
long i;
long r = n%10 + 1;
if (n <= 0)
{
return 0;
}
for (i = 0; i < r; i++)
{
num2 += GetSumOfDigits(n - i);
}
// The magic number 45 is the sum of 1 to 9.
return num2 + 10 * GetSumDigitFrom1toN(n/10 - 1) + (n/10) * 45;
}
Test run:
GetSumDigitFrom1toN(12L): 51
GetSumDigitFrom1toN(123456789L): 4366712385
The time complexity is O(log n).
Sum of digits for 0..99999999 is 10000000 * 8 * (0 + 1 + 2 + ... + 9).
Then calculating the rest (100000000..123456789) using the loop might be fast enough.
For N = 12:
Sum of digits for 0..9 is 1 * 1 * 45. Then use your loop for 10, 11, 12.
For N = 123:
Sum of digits for 0..99 is 10 * 2 * 45. Then use your loop for 100..123.
You see the pattern?
A different approach you can try:
Convert the number to a string, then to a Char array
Sum the ASCII codes for all the chars, minus the code for 0
Example code:
long num = 123456789;
var numChars = num.ToString().ToCharArray();
var zeroCode = Convert.ToByte('0');
var sum = numChars.Sum(ch => Convert.ToByte(ch) - zeroCode);

List of Non-Negative Integers - concatenate into largest possible nr - e.g. [1,2,5] = 521 [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I'm following this blog asking
Five programming problems every Software Engineer should be able to solve in less than 1 hour
I am absolutely stumped by question 4 (5 is a different story too)
Write a function that given a list of non negative integers, arranges them such that they form the largest possible number. For example, given [50, 2, 1, 9], the largest formed number is 95021.
Now the author posted a answer, and I saw an python attempt too:
import math
numbers = [50,2,1,9,10,100,52]
def arrange(lst):
for i in xrange(0, len(lst)):
for j in xrange(0, len(lst)):
if i != j:
comparison = compare(lst[i], lst[j])
if lst[i] == comparison[0]:
temp = lst[j]
lst[j] = lst[i]
lst[i] = temp
return lst
def compare(num1, num2):
pow10_1 = math.floor(math.log10(num1))
pow10_2 = math.floor(math.log10(num2))
temp1 = num1
temp2 = num2
if pow10_1 > pow10_2:
temp2 = (temp2 / math.pow(10, pow10_2)) * math.pow(10, pow10_1)
elif pow10_2 > pow10_1:
temp1 = (temp1 / math.pow(10, pow10_1)) * math.pow(10, pow10_2)
print "Starting", num1, num2
print "Comparing", temp1, temp2
if temp1 > temp2:
return [num1, num2]
elif temp2 > temp1:
return [num2, num1]
else:
if num1 < num2:
return [num1, num2]
else:
return [num2, num1]
print arrange(numbers)
but I'm not going to learn these languages soon. Is anyone willing to share how they would sort the numbers in C# to form the largest number please?
I've also tried straight conversion to C# in VaryCode but when the IComparer gets involved, then it causes erroneous conversions.
The python attempt uses a bubble sort it seems.
Is bubble sort a starting point? What else would be used?
The solution presented uses the approach to sort the numbers in the array in a special way. For example the value 5 comes before 50 because "505" ("50"+"5") comes before "550" ("5"+"50"). The thinking behind this isn't explained, and I'm not convinced that it actually works...
When looking that the problem, I came to this solution:
You can do it recursively. Make a method that loops through the numbers in the array and concatenates each number with the largest value that can be formed by the remaining numbers, to see which one of those is largest:
public static int GetLargest(int[] numbers) {
if (numbers.Length == 1) {
return numbers[0];
} else {
int largest = 0;
for (int i = 0; i < numbers.Length; i++) {
int[] other = numbers.Take(i).Concat(numbers.Skip(i + 1)).ToArray();
int n = Int32.Parse(numbers[i].ToString() + GetLargest(other).ToString());
if (i == 0 || n > largest) {
largest = n;
}
}
return largest;
}
}
If you want to do it by bubble sort, try this:
public static void Main()
{
bool swapped = true;
while (swapped)
{
swapped = false;
for (int i = 0; i < VALUES.Length - 1; i++)
{
if (Compare(VALUES[i], VALUES[i + 1]) > 0)
{
int temp = VALUES[i];
VALUES[i] = VALUES[i + 1];
VALUES[i + 1] = temp;
swapped = true;
}
}
}
String result = "";
foreach (int integer in VALUES)
{
result += integer.ToString();
}
Console.WriteLine(result);
}
public static int Compare(int lhs, int rhs)
{
String v1 = lhs.ToString();
String v2 = rhs.ToString();
return (v1 + v2).CompareTo(v2 + v1) * -1;
}
The Compare method compares the order of two numbers that would create the largest number. When it returns value larger than 0, that means you need to swap.
This is the sorting part:
while (swapped)
{
swapped = false;
for (int i = 0; i < VALUES.Length - 1; i++)
{
if (Compare(VALUES[i], VALUES[i + 1]) > 0)
{
int temp = VALUES[i];
VALUES[i] = VALUES[i + 1];
VALUES[i + 1] = temp;
swapped = true;
}
}
}
It checks to consecutive values in the array and swaps if necessary. After one iteration without swapping, the sort is finished.
Finally, you concatenate the values in the array and print it out.

Categories

Resources