Incorrect values when converting char digits to int - c#

My end goal is to take a number like 29, pull it apart and then add the two integers that result. So, if the number is 29, for example, the answer would be 2 + 9 = 11.
When I'm debugging, I can see that those values are being held, but it appears that other values are also being incorrect in this case 50, 57. So, my answer is 107. I have no idea where these values are coming from and I don't know where to begin to fix it.
My code is:
class Program
{
static void Main(string[] args)
{
int a = 29;
int answer = addTwoDigits(a);
Console.ReadLine();
}
public static int addTwoDigits(int n)
{
string number = n.ToString();
char[] a = number.ToCharArray();
int total = 0;
for (int i = 0; i < a.Length; i++)
{
total = total + a[i];
}
return total;
}
}

As mentioned the issue with your code is that characters have a ASCII code value when you cast to int which doesn't match with the various numerical digits. Instead of messing with strings and characters just use good old math instead.
public static int AddDigits(int n)
{
int total = 0;
while(n>0)
{
total += n % 10;
n /= 10;
}
return total;
}
Modulo by 10 will result in the least significant digit and because integer division truncates n /= 10 will truncate the least significant digit and eventually become 0 when you run out of digits.

Your code is actually additioning the decimal value of the char.
Take a look at https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html
Decimal value of 2 and 9 are 50 and 57 respectively. You need to convert the char into a int before doing your addition.
int val = (int)Char.GetNumericValue(a[i]);

Try this:
public static int addTwoDigits(int n)
{
string number = n.ToString();
char[] a = number.ToCharArray();
int total = 0;
for (int i = 0; i < a.Length; i++)
{
total = total + (int)Char.GetNumericValue(a[i]);
}
return total;
}
Converted number to char always returns ASCII code.. So you can use GetNumericValue() method for getting value instead of ASCII code

Just for fun, I thought I'd see if I could do it in one line using LINQ and here it is:
public static int AddWithLinq(int n)
{
return n.ToString().Aggregate(0, (total, c) => total + int.Parse(c.ToString()));
}
I don't think it would be particularly "clean" code, but it may be educational at best!

You should you int.TryParse
int num;
if (int.TryParse(a[i].ToString(), out num))
{
total += num;
}

Your problem is that you're adding char values. Remember that the char is an integer value that represents a character in ASCII. When you are adding a[i] to total value, you're adding the int value that represents that char, the compiler automatic cast it.
The problem is in this code line:
total = total + a[i];
The code above is equal to this code line:
total += (int)a[i];
// If a[i] = '2', the character value of the ASCII table is 50.
// Then, (int)a[i] = 50.
To solve your problem, you must change that line by this:
total = (int)Char.GetNumericValue(a[i]);
// If a[i] = '2'.
// Then, (int)Char.GetNumericValue(int)a[i] = 2.
You can see this answer to see how to convert a numeric value
from char to int.
At this page you can see the ASCII table of values.

public static int addTwoDigits(int n)
{
string number = n.ToString()
char[] a = number.ToCharArray();
int total = 0;
for (int i = 0; i < a.Length; i++)
{
total += Convert.ToInt32(number[i].ToString());
}
return total;
}

You don't need to convert the number to a string to find the digits. #juharr already explained how you can calculate the digits and the total in a loop. The following is a recursive version :
int addDigit(int total,int n)
{
return (n<10) ? total + n
: addDigit(total += n % 10,n /= 10);
}
Which can be called with addDigit(0,234233433)and returns 27. If n is less than 10, we are counting the last digit. Otherwise extract the digit and add it to the total then divide by 10 and repeat.
One could get clever and use currying to get rid of the initial total :
int addDigits(int i)=>addDigit(0,i);
addDigits(234233433) also returns 27;
If the number is already a string, one could take advantage of the fact that a string can be treated as a Char array, and chars can be converted to ints implicitly :
var total = "234233433".Sum(c=>c-'0');
This can handle arbitrarily large strings, as long as the total doesn't exceed int.MaxValue, eg:
"99999999999999999999".Sum(x=>x-'0'); // 20 9s returns 180
Unless the number is already in string form though, this isn't efficient nor does it verify that the contents are an actual number.

Related

Creating a C# program that calculates sum of the individual digits of a given number

So for practice, I decided to attempt to create a C# program, that calculates the sum of the individual digits of a given (e.g. If I were to input the number 123, the sum should be 6, because 1 + 2 + 3..)
My thought process is that I would use a for loop to iterate through a specific number (I'd have to convert the number first to a string though), add each individual number into a list, and then find the sum of that list, in order to get my answer. However, when I do so, as demonstrated by the code below:
static void Main(string[] args)
{
int num;
int sumOfNum = 0;
List<int> numbersToAdd = new List<int>();
Console.WriteLine("insert number: ");
num = Convert.ToInt32(Console.ReadLine());
string myNum = num.ToString();
for (int i = 0; i < myNum.Length; i++)
{
numbersToAdd.Add(myNum[i]);
}
foreach (int n in numbersToAdd)
{
sumOfNum = numbersToAdd.Sum();
}
Console.WriteLine("the sum is " + sumOfNum);
}
Instead of the output is 6, my output instead is 150. I thought it was weird, so when I decided to iterate through my list, so I can see my values, as shown below:
foreach (int n in numbersToAdd)
{
Console.WriteLine(n);
}
Instead of getting the values 1, 2, and 3, I instead get 49, 50, 51.
Why is that? Is it because of the fact that I'm sending in an index of a string, instead of an actual int? And if so, how can I fix it?
myNum is a string, this means that myNum[i] will return a character and not an int. However, the char is implicitly converted to an int in your case, but you still get the ASCII-value of the character.
In your case, these characters happen to be '1', '2' and '3', which have an ASCII-value of 49, 50 and 51 respectively. To see other ASCII values, search the Internet for 'ASCII table'.
To fix your code, you must convert those ASCII-values back to their decimal value by subtracting the value of the '0'-character:
numbersToAdd.Add(myNum[i] - '0');
Apart from that, you don't have to convert the number to a string, you can use modulus 10 to get the right-most digit: num % 10 and then divide num with 10 to advance to the next digit: num /= 10;. Do this in a loop for as long num differs from zero.
while (num > 0)
{
sumOfNum += num % 10;
num /= 10;
}

Efficient way to count the number of appearances of a digit in a number

I need to count the number of times a single digit (not 0) appears in a number (positive integer) of varying length.
The obvious solution is to convert the number to a string, the digit to a character and iterate over the string to count the number of times the character appears in the string.
static int CountDigitInString(string searchString, char digit)
{
int sum = 0;
for (int i = 0; i < searchString.Length; i++)
{
if (searchString[i] == digit)
sum++;
}
return sum;
}
The problem with this method, however, is that it is too slow for my purposes as I am running it many times.
public static void Run()
{
for (int i = 0; i < 1000000; i++)
{
CountDigitInString(i.ToString(), (char)j);
}
}
After I noted that the process took too much time, the CPU sampling profiler showed me that the problem was with the conversion to string.
So, how do I efficiently count the number of times a digit (single digit only, not a number) appears in a number (of any length)?
Here is more optimized version of #shaitibber solution. It replaces one division with multiplying and returns 1 for 0,0. It is about 20% faster.
static int CountDigitsInString2(int number, int digit)
{
int sum = 0;
do
{
int n2 = number / 10;
if (number - n2 * 10 == digit)
sum++;
number = n2;
} while (number != 0);
return sum;
}
And here is solution about three times faster than that (but does not work for 0 digit, which is not required). It precalculates results for numbers 0..9999.
private static int[][] cache = new int[10][];
private const int cacheSize = 10000;//or 100000
private static int[] initCache(int digit)
{
var ca = cache[digit] = new int[cacheSize];
for (int i = 0; i < ca.Length; ++i)
{
ca[i] = CountDigitsInString2(i, digit);
}
return ca;
}
static int CountDigitsInString3(int number, int digit)
{
var ca = cache[digit] ?? initCache(digit);
int sum = 0;
while (number != 0)
{
int n2 = number / cacheSize;
sum += ca[number - n2 * cacheSize];
number = n2;
};
return sum;
}
I found a way which turned out to be about 3 times as fast on average (checked using a Stopwatch):
static int CountDigitsInString(int number, int digit)
{
int sum = 0;
while (number != 0)
{
if (number % 10 == digit)
sum++;
number /= 10;
}
return sum;
}
EDIT:
I found a way which is over 4 times as fast as the one above. Before I start, note that this solution is valid only for cases in which you are counting appearances of a digit in consecutive numbers.
It occurred to me that if you counted the number of times the digit "d" appeared in a number "A", then you don't neccessarily have to recount the number of times "d" appears in "A + 1" to know what it is.
For example, if I know that the digit 3 appears 4 times in the number 35312336, I can know for a fact that it will still appear 4 times in the next consecutive number 35312337, without actually counting.
The reason I can do this is that the count would only change in one of three cases:
1) When the last digit of "A - 1" was a 9, "A" can change entirely due to numbers being carried over. This is the only case in which we actually have to count (although you could, theoretically, optimize this further by checking the numbers carried over to see if they affect the total but this strikes me as overly complicated).
2) When the last digit of "A - 1" was "d - 1", we know that the number of times "d" appears in "A" has increased by one.
3) When the last digit of "A - 1" was "d", we know that the number of times "d" appears in "A" has decreased by one.
This means that you only have to count the appearances of "d" in "A" using arithmetical operations in one out of 10 cases!
public static void Run()
{
int digit = 1;
int count = 0;
for (int i = 0; i < 100000; i++)
{
int previousLastDigit = (i - 1) % 10;
if (previousLastDigit == (digit - 1))
count++;
else if (previousLastDigit == 9)
count = CountDigitsInString(i, digit);
else if (previousLastDigit == digit)
count--;
Console.WriteLine(digit + " appears " + count + " times in the number " + i);
}
}
The CountDigitsInString function is the one above.
Here is a little snip with LINQ to give you another way to do it (didn't ran a stopwatch)
var number = 11334511;
var digit = 1;
var digitAsChar = Convert.ToChar(digit.ToString().ToLower());
// Occurence will be 4
var occurence = number.ToString().ToLower().Count(s => s == digitAsChar);
I suggest you use LINQ on string.
Source: https://msdn.microsoft.com/en-us/library/mt693025.aspx
static int CountDigitInString(string number, char digit)
{
int count = number.Count(ns => ns == digit);
return count;
}

C# number format: display n significant number of digits?

is there a way to format a double value such that it shows the n siginifacant digits only?
for example I have a double with value 123456, can we have a format string such that it displays the first 3 digits only.
double x=12346;
string s=x.ToString("Some format"); //display 123 only
is that possible?
Although there are formats that would let you drop some or all of the fraction, no format would let you drop some of the significant digits of the whole part of the number.
If you would like to keep the first three digits of the whole number, you need to divide the value so that its whole part has only three digits.
One approach to computing the divisor is taking log10N, checking if it is above 2, and dividing by 10 to the corresponding power:
private static void Print(double x) {
int n = (int)Math.Log10(x);
if (n > 2) {
x /= Math.Pow(10, n-2);
}
Console.WriteLine((int)x);
}
Demo.
You can't format the largest part of the double to only be to 3 sig. fig. but you can split the string. Try:
String s = x.ToString().Substring(0, n);
Where n is the number of significant figures you wish to keep.
I made a console application for this example. I know you need a double or int data type for the number, but I didn't know how manipulate the decimal numbers after the point, so I used a string (if you don't mind, store the number value inside string data type):
string number = "";
string digits = "";
int n = 0;
int count = 0;
number = "45.6";
//number = "456";
n = 3;
if (number.Contains('.')) //If the number has decimals...
{
if (n < number.Length)
{
if (number.IndexOf('.') < n)
{
while (count <= n) //... we will count the number in a different way.
{
if (number[count] != '.')
{
digits = digits + number[count];
}
count++;
}
}
else
{
while (count < n)
{
if (number[count] != '.')
{
digits = digits + number[count];
}
count++;
}
}
}
}
else
{
if (n <= number.Length)
{
while (count < n) //If not, we count without the decimal point.
{
digits = digits + number[count];
count++;
}
}
}
Console.WriteLine("N significant digits: " + digits);
You can try with decimal and integer numbers, but in the code, they both are strings. As I said before, if you don't mind using this data type, this example will help you, if not, you can try with "Substring" function from the String class.

Convert "int" into "char" inside char array

I am trying to do string manipulation. Here's my C# code :
static void Main(string[] args)
{
string input;
string output;
int length;
Console.WriteLine("input = ");
input = Console.ReadLine();
length = input.Length;
if ((input != "") || (length != 0))
{
Random randem = new Random();
int i = -1; //because I do not want the first number to be replaced by the random number
char[] characters = input.ToCharArray();
while (i < length)
{
int num = randem.Next(0, 9);
char num1 = Convert.ToChar(num);
i = i + 2; //so that every next character will be replaced by random number.. :D
characters[i] = num1; //*error* here
}
output = new string(characters);
Console.WriteLine(output);
}
For example:
User input : "i_love_to_eat_fish"
Desired output : "i2l4v1_9o5e8t7f8s2"
notice that the only unchanged character in
the char[] characters is : "i l v _ o e t f s". (desired output from the program)
I've already tried using this code, but still,
keep getting error at characters[i] = num1;
Am I on the right track?
I'm guessing the error you get is IndexOutOfRangeException this is because of the i = i + 2;. The while makes sure that i is less than length, but then adding 2 could result in it being more. Just add a check that it isn't beyond the length.
i = i + 2;
if(i < length)
characters[i] = num1;
Or just change to a for loop.
Random randem = new Random();
char[] characters = input.ToCharArray();
for(int i = 1; i < length; i += 2)
{
int num = randem.Next(1, 10); // max value is exclusive
char num1 = num.ToString()[0];
characters[i] = num1;
}
output = new string(characters);
Console.WriteLine(output);
Also as Shar1er80 points out you're currently converting the digit to the char that has the same ASCII value, and not the the actual characters that represent the digit. The digits 0-9 are represented by the the values 48-57. You can change the call to Random.Next to be:
int num = randem.Next(48, 58); // The upper bound is exclusive, not inclusive
char num1 = (char)num;
Or as Shar1er80 does it
int num = randem.Next(0,10) // Assumming you want digits 0-9
char num1 = num.ToString[0];
Also note that the max value for Random.Next is exclusive, so if you want to include the possibility of using a 9 you have to use an upper bound that is 1 greater than the greatest value you want.
Whenever you reach i = 17 you add 2 to i . That makes i = 19 with length of input equal to 18 that causes out of range exception.
The error you are getting is IndexOutOfTheRangeException, which explains everthing in itself.
It means that index you are feeding to array in the loop is going beyond its length-1 (as arrays have 0-based indexing)
So when you do i+2, you need to check if i+2 is not exceeding i.length-1 at any point of time; which does in your loop.
In general just check if you are supplying indexes between 0 and Array.Length-1
its because you start at index -1, and characters doesn't contain an index of -1.
EDIT: Sorry no the corrct answer is it must be while(i < length - 2)
Change this line
char num1 = Convert.ToChar(num);
To
char num1 = num.ToString()[0];
Then... Put
characters[i] = num1;
In an if block
if (i < length)
characters[i] = num1;

Evenly divide in c#

In c# how do I evenly divide 100 into 7?
So the result would be
16
14
14
14
14
14
14
The code below is incorrect as all 7 values are set to 15 (totalling 105).
double [] vals = new double[7];
for (int i = 0; i < vals.Length; i++)
{
vals[i] = Math.Ceiling(100d / vals.Length);
}
Is there an easy way to do this in c#?
Thanks
To get my suggested result of 15, 15, 14, 14, 14, 14, 14:
// This doesn't try to cope with negative numbers :)
public static IEnumerable<int> DivideEvenly(int numerator, int denominator)
{
int rem;
int div = Math.DivRem(numerator, denominator, out rem);
for (int i=0; i < denominator; i++)
{
yield return i < rem ? div+1 : div;
}
}
Test:
foreach (int i in DivideEvenly(100, 7))
{
Console.WriteLine(i);
}
Here you go:
Func<int, int, IEnumerable<int>> f = (a, b) =>
Enumerable.Range(0,a/b).Select((n) => a / b + ((a % b) <= n ? 0 : 1))
Good luck explaining it in class though :)
Since this seems to be homework, here is a hint and not the full code.
You are doing Math.Ceiling and it converts 14.28 into 15.
The algorithm is this
Divide 100 by 7, put the result in X
Get the highest even number below X and put this in Y.
Multiply Y by 7 and put the answer in Z.
Take Z away from 100.
The answer is then 6 lots of Y plus whatever the result of step 4 was.
This algorithm may only work for this specific instance.
I'm sure you can write that in C#
Not sure if this is exactly what you are after, but I would think that if you use Math.ceiling you will always end up with too big a total. Math.floor would underestimate and leave you with a difference that can be added to one of your pieces as you see fit.
For example by this method you might end up with 7 lots of 14 giving you a remainder of 2. You can then either put this 2 into one of your pieces giving you the answer you suggested, or you could split it out evenly and add get two pieces of 15 (as suggested in one of the comments)
Not sure why you are working with doubles but wanting integer division semantics.
double input = 100;
const int Buckets = 7;
double[] vals = new double[Buckets];
for (int i = 0; i < vals.Length; i++)
{
vals[i] = Math.Floor(input / Buckets);
}
double remainder = input % Buckets;
// give all of the remainder to the first value
vals[0] += remainder;
example for ints with more flexibility,
int input = 100;
const int Buckets = 7;
int [] vals = new int[Buckets];
for (int i = 0; i < vals.Length; i++)
{
vals[i] = input / Buckets;
}
int remainder = input % Buckets;
// give all of the remainder to the first value
vals[0] += remainder;
// If instead you wanted to distribute the remainder evenly,
// priority to first
for (int r = 0; r < remainder;r++)
{
vals[r % Buckets] += 1;
}
It is worth pointing out that the double example may not be numerically stable in that certain input values and bucket sizes could result in leaking fractional values.

Categories

Resources