Why aren't these integer number reaching the cap? - c#

I wanted to try creating a console app that could give me the results of evaluating the Collatz conjecture with several different numbers, but when the program runs up to 113,000 the numbers stop calculating.
In order to do so, I used a (double,int) for calculations.
Here is my reasoning:
if an odd double is divided by 2, you will get a decimal: 2.3,2.4,2.5, and so on; however, if an odd integer is divided by 2 you will get another integer. Using this knowledge, if a number is odd, then the decimal version of the number will not be equal to the integer version.
However, after doing a few tests, I found that the numbers stopped at 113,000. When the max for integers and doubles should be higher.
These are the results.
[1]: https://i.stack.imgur.com/xdHpT.png
The following code bellow checks if a number is even or odd. If the number is even, the number is divided by two, and if the number is odd, the number is multiplied by three and added by 1.
There are no errors listed in the debug screen. My expected result is for the list of numbers to continue up to the int maximum.
static (double,int) Checker(double n1, int n2)
{
double newn1 = n1;
int newn2 = n2;
if(n1/2==n2/2)
{
newn1 = n1 / 2;
newn2 = n2 / 2;
}
else
{
newn1 = (n1 * 3) + 1;
newn2 = (n2 * 3) + 1;
}
return (newn1,newn2);
}
The part of code below ensures that each number is calculated using the Collatz conjecture until a result of 1 is released or j = (1,1)
static void Main(string[] args)
{
int v = 2;
int timer = 1;
int savedv = 1;
bool run = true;
bool reached = false;
(double, int) j;
j.Item2 = -5;
j.Item1 = 0;
while (1 == 1)
{
while (1==1)
{
while (reached == false)
{
if (timer == 1)
{ savedv = v;
}
j = Checker(v, v);
v = j.Item2;
timer += 1;
if (j == (1, 1))
{
v = savedv;
reached = true;
}
}
if (reached == true)
{
Console.WriteLine("The number" + " " + v + " " + "follows the sequence, and 1 was reached on a timer of" + " "+ timer +"\n" + "Total steps:"+" " + (timer-1));
v += 1;
timer = 1;
reached = false;
}
}
}
}

The core problem you're hitting is that Collatz(113383) has an intermediate value that surpasses Int32.MaxVaue.
Here's a simpler & faster implementation to demonstrate that point;
private static void Collatz()
{
for (ulong i = 1; ; i++)
{
var j = i;
var steps = 0;
while (j != 1)
{
steps++;
if ((j & 1) == 0)
j = j >> 1;
else
{
j = (j << 1) + j + 1; // *3 via shifting * addition
if (j >= Int32.MaxValue)
break;
}
}
if ((i%10000) == 0 || j != 1)
Console.WriteLine($"{i} hit {j} after {steps} steps");
if (j != 1)
break;
}
}
Outputs;
10000 hit 1 after 29 steps
20000 hit 1 after 30 steps
30000 hit 1 after 178 steps
40000 hit 1 after 31 steps
50000 hit 1 after 127 steps
60000 hit 1 after 179 steps
70000 hit 1 after 81 steps
80000 hit 1 after 32 steps
90000 hit 1 after 164 steps
100000 hit 1 after 128 steps
110000 hit 1 after 92 steps
113383 hit 2482111348 after 120 steps

Related

Detection a two different math cases using c#

I have this code that should run "Amount" times. The code has to do a math equation called
collatz conjecture, how it works is you get a number, if its odd you have to * by 3 and than add 1 but if its even you have to divide it by 2, this should go on until the number hits one, if the number does it one the variable Ver should be added but one otherwise this should get in a never ending loop, The problem is I don't know how to detect that loop. The code bellow is the whole thing without the loop detection and when I run it 1 million times it worked fine expect 432 numbers specifically that should not get in that loop.
The problem is you never know if the math equation is still happening or is it a special case that will never hit the number 1.
using System.Collections.Generic;
using System;
int Amount = 1000000;
int Ver = 0;
Amount++;
for (int i = 1; i < Amount; i++)
{
int i2 = i;
while (i2 > 1)
{
if (i2 % 2 == 0) {
int i3 = i2 / 2;
i2 = i3;
}
else
{
i2 = (i2 * 3) + 1;
}
}
if (i2 == 1 || i2==4 || i2==2)
Ver++;
}
Amount--;
Console.WriteLine(Ver + " of "+ Amount + " numbers were verified.");
A good idea would be if the program was stuck on number for too long (More than 2 or 3 minuets) to Maybe ask in the console to see if the program should continue on a number or should it skip that number. I have tried putting on timer each time it gets to a new number but it will slow the program by almost 3 or 4 times. Does anyone know a faster way to do that?
This solution does not pretend to be academic.
Due to link you provided you must use ulong (UInt64) at least instead of int (Int32)
You can use TPL DataFlow with CancellationToken:
using System.Collections.Concurrent;
using System.Threading.Tasks.Dataflow;
const ulong start = 20_000_001;
const ulong amount = 10_000_000;
const ulong maxIterations = 1000_0000;
ulong verified = 0;
ConcurrentBag<ulong> canceledNumbers = new ConcurrentBag<ulong>();
ConcurrentBag<ulong> overflowNumbers = new ConcurrentBag<ulong>();
var actionBlock = new ActionBlock<ulong>(CollatzAction,
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount * 2, // Remove 2 if you don't have hyperthreading
BoundedCapacity = Environment.ProcessorCount * 4, // Back pressure to avoid the memory overhead
});
for (ulong i = start; i < start + amount; i++)
{
await actionBlock.SendAsync(i).ConfigureAwait(false);
}
actionBlock.Complete();
await actionBlock.Completion.ConfigureAwait(false);
Console.WriteLine($"{verified} of {amount} numbers were verified, {canceledNumbers.Count} were canceled.");
if (!canceledNumbers.IsEmpty)
{
Console.WriteLine($"Canceled numbers are: {string.Join(", ", canceledNumbers)}");
}
if (!overflowNumbers.IsEmpty)
{
Console.WriteLine($"Overflow numbers are: {string.Join(", ", overflowNumbers)}");
}
void CollatzAction(ulong i)
{
try
{
var (oneIsReached, isCanceled) = Collatz(i);
if (oneIsReached)
{
Interlocked.Increment(ref verified);
}
else if (isCanceled)
{
canceledNumbers.Add(i);
}
}
catch (OverflowException)
{
overflowNumbers.Add(i);
}
}
(bool oneIsReached, bool isCanceled) Collatz(ulong i)
{
ulong iteration = 1;
while (i > 1 && iteration <= maxIterations)
{
i = (i & 1) == 0 // the same as i % 2 == 0 but faster
? i / 2
: checked(i * 3 + 1);
iteration++;
}
return (i == 1, iteration > maxIterations);
}
You can try to replace ulong with BigInteger to avoid overflows, but it's much slower:
using System.Collections.Concurrent;
using System.Numerics;
using System.Threading.Tasks.Dataflow;
BigInteger start = 100_000_001;
const ulong amount = 10_000_000;
const ulong maxIterations = 1000_0000;
ulong verified = 0;
ConcurrentBag<BigInteger> canceledNumbers = new ConcurrentBag<BigInteger>();
var actionBlock = new ActionBlock<BigInteger>(CollatzAction,
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount * 2, // Remove 2 if you don't have hyperthreading
BoundedCapacity = Environment.ProcessorCount * 4, // Back pressure to avoid the memory overhead
});
for (BigInteger i = start; i < start + amount; i++)
{
await actionBlock.SendAsync(i).ConfigureAwait(false);
}
actionBlock.Complete();
await actionBlock.Completion.ConfigureAwait(false);
Console.WriteLine($"{verified} of {amount} numbers were verified, {canceledNumbers.Count} were canceled.");
if (!canceledNumbers.IsEmpty)
{
Console.WriteLine($"Canceled numbers are: {string.Join(", ", canceledNumbers)}");
}
void CollatzAction(BigInteger i)
{
var (oneIsReached, isCanceled) = Collatz(i);
if (oneIsReached)
{
Interlocked.Increment(ref verified);
}
else if (isCanceled)
{
canceledNumbers.Add(i);
}
}
(bool oneIsReached, bool isCanceled) Collatz(BigInteger i)
{
ulong iteration = 1;
while (i > 1 && iteration <= maxIterations)
{
i = (i & 1) == 0 // the same as i % 2 == 0 but faster
? i / 2
: i * 3 + 1;
iteration++;
}
return (i == 1, iteration > maxIterations);
}

Calculating the correct length of string per line with Page X/Y

I got asked a question and now I am kicking myself for not being able to come up with the exact/correct result.
Imagine we have a function that splits a string into multiple lines but each line has to have x number of characters before we "split" to the new line:
private string[] GetPagedMessages(string input, int maxCharsPerLine) { ... }
For each line, we need to incorporate, at the end of the line "x/y" which is basically 1/4, 2/4 etc...
Now, the paging mechanism must also be part of the length restriction per line.
I have been overworked and overthinking and tripping up on things and this seems pretty straight forward but for the life of me, I cannot figure it out! What am I not "getting"?
What am I interested in? The calculation and some part of the logic but mainly the calculation of how many lines are required to split the input based on the max chars per line which also needs to include the x/y.
Remember: we can have more than a single digit for the x/y (i.e: not just 1/4 but also 10/17 or 99/200)
Samples:
input = "This is a long message"
maxCharsPerLine = 10
output:
This i 1/4 // << Max 10 chars
s a lo 2/4 // << Max 10 chars
ng mes 3/4 // << Max 10 chars
sage 4/4 // << Max 10 chars
Overall the logic is simple but its just the calculation that is throwing me off.
The idea: First, find how many digits is the number of lines:
(n = input.Length, maxCharsPerLine = 10)
if n <= 9*(10-4) ==> 1 digit
if n <= 9*(10-5) + 90*(10-6) ==> 2 digits
if n <= 9*(10-6) + 90*(10-7) + 900*(10-8) ==> 3 digits
if n <= 9*(10-7) + 90*(10-8) + 900*(10-9) + 9000*(10-10) ==> No solution
Then, subtract the spare number of lines. The solution:
private static int GetNumberOfLines(string input, int maxCharsPerLine)
{
int n = input.Length;
int x = maxCharsPerLine;
for (int i = 4; i < x; i++)
{
int j, sum = 0, d = 9, numberOfLines = 0;
for (j = i; j <= i + i - 4; j++)
{
if (x - j <= 0)
return -1; // No solution
sum += d * (x - j);
numberOfLines += d;
d *= 10;
}
if (n <= sum)
return numberOfLines - (sum - n) / (x - j + 1);
}
return -2; // Invalid
}
Usage:
private static string[] GetPagedMessages(string input, int maxCharsPerLine)
{
int numberOfLines = GetNumberOfLines(input, maxCharsPerLine);
if (numberOfLines < 0)
return null;
string[] result = new string[numberOfLines];
int spaceLeftForLine = maxCharsPerLine - numberOfLines.ToString().Length - 2; // Remove the chars of " x/y" except the incremental 'x'
int inputPosition = 0;
for (int line = 1; line < numberOfLines; line++)
{
int charsInLine = spaceLeftForLine - line.ToString().Length;
result[line - 1] = input.Substring(inputPosition, charsInLine) + $" {line}/{numberOfLines}";
inputPosition += charsInLine;
}
result[numberOfLines-1] = input.Substring(inputPosition) + $" {numberOfLines}/{numberOfLines}";
return result;
}
A naive approach is to start counting the line lengths minus the "pager"'s size, until the line count changes in size ("1/9" is shorter than "1/10", which is shorter than "11/20", and so on):
private static int[] GetLineLengths(string input, int maxCharsPerLine)
{
/* The "pager" (x/y) is at least 4 characters (including the preceding space) and at most ... 8?
* 7/9 (4)
* 1/10 (5)
* 42/69 (6)
* 3/123 (6)
* 42/420 (7)
* 999/999 (8)
*/
int charsRemaining = input.Length;
var lineLengths = new List<int>();
// Start with " 1/2", (1 + 1 + 2) = 4 length
var highestLineNumberLength = 1;
var lineNumber = 0;
do
{
lineNumber++;
var currentLineNumberLength = lineNumber.ToString().Length; // 1 = 1, 99 = 2, ...
if (currentLineNumberLength > highestLineNumberLength)
{
// Pager size changed, reset
highestLineNumberLength = currentLineNumberLength;
lineLengths.Clear();
lineNumber = 0;
charsRemaining = input.Length;
continue;
}
var pagerSize = currentLineNumberLength + highestLineNumberLength + 2;
var lineLength = maxCharsPerLine - pagerSize;
if (lineLength <= 0)
{
throw new ArgumentException($"Can't split input of size {input.Length} into chunks of size {maxCharsPerLine}");
}
lineLengths.Add(lineLength);
charsRemaining -= lineLength;
}
while (charsRemaining > 0);
return lineLengths.ToArray();
}
Usage:
private static string[] GetPagedMessages(string input, int maxCharsPerLine)
{
if (input.Length <= maxCharsPerLine)
{
// Assumption: no pager required for a message that takes one line
return new[] { input };
}
var lineLengths = GetLineLengths(input, maxCharsPerLine);
var result = new string[lineLengths.Length];
// Cut the input and append the pager
var previousIndex = 0;
for (var i = 0; i < lineLengths.Length; i++)
{
var lineLength = Math.Min(lineLengths[i], input.Length - previousIndex); // To cater for final line being shorter
result[i] = input.Substring(previousIndex, lineLength) + " " + (i + 1) + "/" + lineLengths.Length;
previousIndex += lineLength;
}
return result;
}
Prints, for example:
This 1/20
is a 2/20
long 3/20
strin 4/20
g tha 5/20
t wil 6/20
l spa 7/20
n mor 8/20
e tha 9/20
n te 10/20
n li 11/20
nes 12/20
beca 13/20
use 14/20
of i 15/20
ts e 16/20
norm 17/20
ous 18/20
leng 19/20
th 20/20

Calculate 2^(n) where 0<n<10000

So, this is my problem to solve:
I want to calculate 2^(n) where 0 < n< 10000
I am representing each element of array as a space where 4digit number should be "living" and if extra digit appears, I am replacing it to the next element of this array.
The principle I am using looks like this:
The code I am using is the following:
static string NotEfficient(int power)
{
if (power < 0)
throw new Exception("Power shouldn't be negative");
if (power == 0)
return "1";
if (power == 1)
return "2";
int[] A = new int[3750];
int current4Digit = 0;
//at first 2 is written in first element of array
A[current4Digit] = 2;
int currentPower = 1;
while (currentPower < power)
{
//multiply every 4digit by 2
for (int i = 0; i <= current4Digit; i++)
{
A[i] *= 2;
}
currentPower++;
//checking every 4digit if it
//contains 5 digit and if yes remove and
//put it in next 4digit
for (int i = 0; i <= current4Digit; i++)
{
if (A[i] / 10000 > 0)
{
int more = A[i] / 10000;
A[i] = A[i] % 10000;
A[i + 1] += more;
//if new digit should be opened
if (i + 1 > current4Digit)
{
current4Digit++;
}
}
}
}
//getting data from array to generate answer
string answer = "";
for (int i = current4Digit; i >= 0; i--)
{
answer += A[i].ToString() + ",";
}
return answer;
}
The problem I have is that it doesn't display correctly the number, which contains 0 in reality. for example 2 ^ (50) = 1 125 899 906 842 624 and with my algorithm I get 1 125 899 96 842 624 (0 is missing). This isn't only for 50...
This happens when I have the following situation for example:
How I can make this algorithm better?
Use BigInteger, which is already included in .Net Core or available in the System.Runtime.Numerics Nuget Package.
static string Efficient(int power)
{
var result = BigInteger.Pow(2, power);
return result.ToString(CultureInfo.InvariantCulture);
}
On my machine, NotEfficient takes roughly 80ms, where Efficient takes 0.3ms. You should be able to manipulate that string (if I'm understanding your problem statement correctly):
static string InsertCommas(string value)
{
var sb = new StringBuilder(value);
for (var i = value.Length - 4; i > 0; i -= 4)
{
sb.Insert(i, ',');
}
return sb.ToString();
}
One way to resolve this is to pad your 4-digit numbers with leading zeroes if they are less than four digits by using the PadLeft method:
answer += A[i].ToString().PadLeft(4, '0') + ",";
And then you can use the TrimStart method to remove any leading zeros from the final result:
return answer.TrimStart('0');

How to do the loop and solve the following

I'm supposed to code a program that writes out a division just like in school.
Example:
13:3=4.333333333333
13
1
10
10
10....
So my approach was:
Solve the division then get the solution in a List.
Then question if the first number (in this case 1) is divisible by 3.
If not put it down and add the second number and so on...
I managed to do this the first time. It's sloppy but works. The problem is that it only works with numbers that when divided get to have a decimal in it.
Exapmle:
123:13
This is the first code:
do
{
for (int number = 1; number <= divNum; number++)
if (number % divisor == 0) countH++;
for (int i = 0; i < count; i++)
Console.Write(" ");
if ((c = divNum % divisor ) < divisor )
{
Console.WriteLine(" " + ((divNum- (countH * divisor ))) * 10);
}
else Console.WriteLine(" " + (divNum- (countH * divisor )));
c = divNum % divisor ;
if (c < divisor )
{
divNum = c * 10;
}
count++; countH = 0;
} while ((divNum >= divisor ) && (count < x));
Any ideas or help? Sorry if this is a bad question.
************ added
Try of a better explanation:
1 cant be divided by 13, so it goes down, we get the 2 down and try 12 divided by 13, still nothing so we get the 3 down and try 123:13, 13 goes 9 times in 123 so we have 123-9*13 = 6 the six goes down we write 9 in the result. We try 6:13 not going so we drop a 0 next to 6. Next we try 60:13, 13 goes 4 times so 60-4*13 = 8, we get the 8 down. And so on..
123:13=9.46153....
123
60
80
20
70
50
....
Something like this should work. Not the fastest solution most likely, but should do the job.
var number = 123;
var b = 12;
int quotient;
double remainder = number;
var x = 10;
do
{
quotient = (int)Math.Floor(remainder / b);
remainder = remainder - (quotient * b);
for (int i = 0; i < count; i++)
Console.Write(" ");
remainder *= 10;
Console.WriteLine(" " + remainder);
count++;
} while ((remainder > 0) && (count < x));

Why aren't 10 and 100 considered Kaprekar numbers?

I'm trying to do the Modified Kaprekar Numbers problem (https://www.hackerrank.com/challenges/kaprekar-numbers) which describes a Kaprekar number by
Here's an explanation from Wikipedia about the ORIGINAL Kaprekar
Number (spot the difference!): In mathematics, a Kaprekar number for a
given base is a non-negative integer, the representation of whose
square in that base can be split into two parts that add up to the
original number again. For instance, 45 is a Kaprekar number, because
45² = 2025 and 20+25 = 45.
and what I don't understand is why 10 and 100 aren't Kaprekar numbers.
10^2 = 1000 and 10 + 00 = 10
Right?
So my solution
// Returns the number represented by the digits
// in the range arr[i], arr[i + 1], ..., arr[j - 1].
// If there are no elements in range, return 0.
static int NumberInRange(int[] arr, int i, int j)
{
int result = 0;
for(; i < j; ++i)
{
result *= 10;
result += arr[i];
}
return result;
}
// Returns true or false depending on whether k
// is a Kaprekar number.
// Example: IsKaprekar(45) = true because 45^2=2025 and 20+25=45
// Example: IsKaprekar(9) = false because the set of the split
// digits of 7^2=49 are {49,0},{4,9} and
// neither of 49+0 or 4+9 equal 7.
static bool IsKaprekar(int k)
{
int square = k * k;
int[] digits = square.ToString().Select(c => (int)Char.GetNumericValue(c)).ToArray();
for(int i = 0; i < digits.Length; ++i)
{
int right = NumberInRange(digits, 0, i);
int left = NumberInRange(digits, i, digits.Length);
if((right + left) == k)
return true;
}
return false;
}
is saying all the Kaprekar numbers between 1 and 100 are
1 9 10 45 55 99 100
whereas the "right" answer is
1 9 45 55 99
In 100+00 the right is 00, which is wrong because in a kaprekar number the right may start with zero (ex: 025) but cannot be entirely 0.
Therefore you can put a condition in the loop that
if(right==0)
return false;
The reason is because 10 x 10 = 100. Then you substring the right part with a length equals d = 2, that is digit count of original value (10), then the left part would be 1.
So l = 1 and r = 00, l + r = 1, that is not equals to 10.
The same for 100. 100 x 100 = 10000. l = 10, r = 000, so l + r = 10 not equal 100.
Here is my solution in JAVA.
static void kaprekarNumbers(int p, int q) {
long[] result = IntStream.rangeClosed(p, q).mapToLong(Long::valueOf)
.filter(v -> {
int d = String.valueOf(v).length();
Long sq = v * v;
String sqSt = sq.toString();
if (sqSt.length() > 1) {
long r = Long.parseLong(sqSt.substring(sqSt.length() - d));
long l = Long.parseLong(sqSt.substring(0, sqSt.length() - d));
return r + l == v;
} else return v == 1;
}).toArray();
if (result.length > 0) {
for (long l : result) {
System.out.print(l + " ");
}
} else {
System.out.println("INVALID RANGE");
}
}
How about something like this.
static bool IsKaprekar(int k)
{
int t;
for (int digits = new String(k).length(); digits > 0; digits--, t *= 10);
long sq = k * k;
long first = sq / t;
long second = sq % t;
return k == first + second;
}
find a number to divide and mod the square with in order to split it. This number should be a factor of 10 based on the number of digits in the original number.
calculate the square.
split the square.
compare the original to the sum of the splits.

Categories

Resources