Hi I am currently teaching myself C# using different books and online solutions, there is one exercise that i cant really get my head around. I had to divide a number by another number in C# using iteration and subtraction but the remainder had to be displayed at the end. I figured out that I could use a while loop to keep dividing one number by the other (lets say 400 / 18) but how to display the decimal at the end from the int number was the part I could not get my head around.
Any help would be greatly appriciated :)
So let's think about this outside the C# language. Because this is really just a math problem to solve.
If you've got 400/18, and you are going to use iteration and subtraction, all you are doing is saying "how many times can I subtract 18 from 400?", right?
So that's going to look something like this:
remainder = 400
value = 18
while (remainder > value)
remainder = remainder - value
Once you exit that while loop, you've got your remainder.
You could use the modulus operator "%" to solve this in one step but based on what you wrote, this is what you would do.
The remainder you've got is can be expressed as so:
double theDecimalValue = (double)remainder/value;
Assuming you were dealing with integers, you'd just cast the remainder value to avoid the truncating integer division that will take place otherwise.
if you need the remainder the easy and right way is
int reminder = 400%18;
if you HAVE TO using a loop you have to :
check if number is less than the divisor or whatever it's called
2a.if yes exit from the loop and show the number
2b if not remove divisor from number and go on next iteration
Related
Basically, my question now is how would I compare the user generated numbers to the computer generated numbers? For example, if the computer shoots out 932 and user puts 912 I would need to be able to say there were matching numbers in the 9 and 2. I'm not sure how I would do that.
Here's a basic overview of what you'll need to do.
Note that the modulus operator (%) returns the remainder of a division operation. So, for example,
6 % 4 == 2
This is useful to you, because
x % 10
will equal the digit in the one's place.
Run this through a loop dividing the input by 10 each iteration and you'll have what you need.
With below code, you will get integer array into intArray from user input
string num3Digit = Console.ReadLine();
var intArray = num3Digit.Select(x=>Convert.ToInt32(x.ToString()));
This is similar to generating a list of consecutive numbers using some nested for loops to add 1 to a number, then display the number. What I'm having trouble is figuring out how to generate a list of consecutive numbers between say 10^26 and 10^27 without using scientific notation to display the number. I'm thinking of using an int[26] but I can't figure out or wrap my head around is how to add the 1 to the higher index (say i[25]) once I've reached 10 and continue with the count until 10^27 is reached.
If you're not doing any calculations beyond incrementing the number, consider representing it as a string and adding 1 in the same way you'd do manual arithmetic:
Initialize the string to whatever number you want to start with.
Add 1 to the rightmost (numeric) character.
If it's <= '9' you're done.
Otherwise, set it to '0' and add 1 to the next character to the left.
Repeat the carrying process until you're done.
I am not sure what you mean by larger than a Bigint, Do you mean a System.Uint64 or a System.Numerics.BigInteger? If you mean BigInteger, the only limit on size is the OutOfMemory exception that could get thrown when working with obscenely large numbers.
Note that BigInteger is immutable so doing somthing like myBigInt++ will create a new object and can cause a performance problem if in a tight loop. See the MSDN's notes on the subject for further informatin
Given that I have two floats, a and b, and only care if they are "approximately equal", would something similar to the following work reliably, or would be it still be subject to precision issues?
eg:
Math.Round(a) == Math.Round(b)
Alternatively, is there a way to reliably round them to the nearest integer? If the above doesn't work, then I assume simply doing (int)Math.Round(a) won't be reliable either.
EDIT: I should have predicted I'd get answers like this, but I'm not trying to determine 'closeness' of the two values. Assuming the logic above is sound, will the above work, or is there a chance that I will get something like 3.0 == 3.0001?
Nothing of this kind will work. There is always a sharp boundary when very similar numbers will be rounded to different numbers.
In your first example think of a=0.4999999 and b=0.5000001. Very close but will round to different integers.
Another problem is that if the numbers are large rounding to an integer will have no effect at all. And even very close(relative) numbers will already an absolute difference >1.
If you care about determinism, you're out of luck with float and double. You just can't get those deterministic on .net. Use Decimal.
IF you really want it reliable then you will have to use Decimal instead of float... although that is much slower...
EDIT:
With ((int)Math.Round(a)) == ((int)Math.Round(b)) you avoid the problem 3.0 == 3.0001 BUT all the other pitfalls mentioned your post and in the answers will still apply...
You can complicate the logic to try to make it a bit more reliable (example see below which could be packaged nicely into some method) but it will never be really reliable...
// 1 = near, 2 = nearer, 3 = even nearer, 4 = nearest
int HowNear = 0;
if (((int)Math.Round(a)) == ((int)Math.Round(b)))
HowNear++;
if (((int)Math.Floor(a)) == ((int)Math.Floor(b)))
HowNear++;
if (((int)Math.Ceiling(a)) == ((int)Math.Ceiling(b)))
HowNear++;
if (Math.Round(a) == Math.Round(b))
HowNear++;
The correct way to convert from double/float to integers is:
(int)Math.Round(a)
having done this you will always get whole numbers which can be tested for equality. If you have numbers which you know are going to be virtually whole numbers (e.g. the result of 6.0/3.0) then this will work great. The recommended way of checking two numbers which are doubles/floats are approximately equal is:
Math.Abs(a-b)<tolerance
where tolerance is a double value that determines how similar they should be, for example, if you want them to be within 1 unit of each other you could use a tolerance of 1.0 which would give you similar accuracy to Math.Round and comparing the results, but is well behaved when you get two values which are very close to half way between two integers.
You could use Floor or Ceieling methods right to rounding of the values.
"approximately equal" is your answer actually, a pseudoexample:
double tollerance = 0.03;
if(Math.Abs(a-b)<=tollerance )
// these numbers are equal !
else
//non equal
EDIT
Or if you want to be more "precise":
int aint = (int)(a*100); // 100 is rounding tollerance
int bint = (int)(b*100); // 100 is rounding tollerance
and after
if(Math.Abs(aint -bint )<=tollerance ) // tollerance has to be integer in this case, obviously
// these numbers are equal !
else
//non equal
For a clever and complicated reason that I don't really want to explain (because it involves making a timer in an extremely ugly and hacky way), I wrote some C# code sort of like this:
int i = 0;
while (i >= 0) i++; //Should increment forever
Console.Write(i);
I expected the program to hang forever or crash or something, but, to my surprise, after waiting for about 20 seconds or so, I get this ouput:
-2147483648
Well, programming has taught me many things, but I still cannot grasp why continually incrementing a number causes it to eventually be negative...what's going on here?
In C#, the built-in integers are represented by a sequence of bit values of a predefined length. For the basic int datatype that length is 32 bits. Since 32 bits can only represent 4,294,967,296 different possible values (since that is 2^32), clearly your code will not loop forever with continually increasing values.
Since int can hold both positive and negative numbers, the sign of the number must be encoded somehow. This is done with first bit. If the first bit is 1, then the number is negative.
Here are the int values laid out on a number-line in hexadecimal and decimal:
Hexadecimal Decimal
----------- -----------
0x80000000 -2147483648
0x80000001 -2147483647
0x80000002 -2147483646
... ...
0xFFFFFFFE -2
0xFFFFFFFF -1
0x00000000 0
0x00000001 1
0x00000002 2
... ...
0x7FFFFFFE 2147483646
0x7FFFFFFF 2147483647
As you can see from this chart, the bits that represent the smallest possible value are what you would get by adding one to the largest possible value, while ignoring the interpretation of the sign bit. When a signed number is added in this way, it is called "integer overflow". Whether or not an integer overflow is allowed or treated as an error is configurable with the checked and unchecked statements in C#. The default is unchecked, which is why no error occured, but you got that crazy small number in your program.
This representation is called 2's Complement.
The value is overflowing the positive range of 32 bit integer storage going to 0xFFFFFFFF which is -2147483648 in decimal. This means you overflow at 31 bit integers.
It's been pointed out else where that if you use an unsigned int you'll get different behaviour as the 32nd bit isn't being used to store the sign of of the number.
What you are experiencing is Integer Overflow.
In computer programming, an integer overflow occurs when an arithmetic operation attempts to create a numeric value that is larger than can be represented within the available storage space. For instance, adding 1 to the largest value that can be represented constitutes an integer overflow. The most common result in these cases is for the least significant representable bits of the result to be stored (the result is said to wrap).
int is a signed integer. Once past the max value, it starts from the min value (large negative) and marches towards 0.
Try again with uint and see what is different.
Try it like this:
int i = 0;
while (i >= 0)
checked{ i++; } //Should increment forever
Console.Write(i);
And explain the results
What the others have been saying. If you want something that can go on forever (and I wont remark on why you would need something of this sort), use the BigInteger class in the System.Numerics namespace (.NET 4+). You can do the comparison to an arbitrarily large number.
It has a lot to do with how positive numbers and negative numbers are really stored in memory (at bit level).
If you're interested, check this video: Programming Paradigms at 12:25 and onwards. Pretty interesting and you will understand why your code behaves the way it does.
This happens because when the variable "i" reaches the maximum int limit, the next value will be a negative one.
I hope this does not sound like smart-ass advice, because its well meant, and not meant to be snarky.
What you are asking is for us to describe that which is pretty fundamental behaviour for integer datatypes.
There is a reason why datatypes are covered in the 1st year of any computer science course, its really very fundamental to understanding how and where things can go wrong (you can probably already see how the behaviour above if unexpected causes unexpected behaviour i.e. a bug in your application).
My advice is get hold of the reading material for 1st year computer science + Knuth's seminal work "The art of computer pragramming" and for ~ $500 you will have everything you need to become a great programmer, much cheaper than a whole Uni course ;-)
I'm trying to determine the number of digits in a c# ulong number, i'm trying to do so using some math logic rather than using ToString().Length. I have not benchmarked the 2 approaches but have seen other posts about using System.Math.Floor(System.Math.Log10(number)) + 1 to determine the number of digits.
Seems to work fine until i transition from 999999999999997 to 999999999999998 at which point, it i start getting an incorrect count.
Has anyone encountered this issue before ?
I have seen similar posts with a Java emphasis # Why log(1000)/log(10) isn't the same as log10(1000)? and also a post # How to get the separate digits of an int number? which indicates how i could possibly achieve the same using the % operator but with a lot more code
Here is the code i used to simulate this
Action<ulong> displayInfo = number =>
Console.WriteLine("{0,-20} {1,-20} {2,-20} {3,-20} {4,-20}",
number,
number.ToString().Length,
System.Math.Log10(number),
System.Math.Floor(System.Math.Log10(number)),
System.Math.Floor(System.Math.Log10(number)) + 1);
Array.ForEach(new ulong[] {
9U,
99U,
999U,
9999U,
99999U,
999999U,
9999999U,
99999999U,
999999999U,
9999999999U,
99999999999U,
999999999999U,
9999999999999U,
99999999999999U,
999999999999999U,
9999999999999999U,
99999999999999999U,
999999999999999999U,
9999999999999999999U}, displayInfo);
Array.ForEach(new ulong[] {
1U,
19U,
199U,
1999U,
19999U,
199999U,
1999999U,
19999999U,
199999999U,
1999999999U,
19999999999U,
199999999999U,
1999999999999U,
19999999999999U,
199999999999999U,
1999999999999999U,
19999999999999999U,
199999999999999999U,
1999999999999999999U
}, displayInfo);
Thanks in advance
Pat
log10 is going to involve floating point conversion - hence the rounding error. The error is pretty small for a double, but is a big deal for an exact integer!
Excluding the .ToString() method and a floating point method, then yes I think you are going to have to use an iterative method but I would use an integer divide rather than a modulo.
Integer divide by 10. Is the result>0? If so iterate around. If not, stop.
The number of digits is the number of iterations required.
Eg. 5 -> 0; 1 iteration = 1 digit.
1234 -> 123 -> 12 -> 1 -> 0; 4 iterations = 4 digits.
I would use ToString().Length unless you know this is going to be called millions of times.
"premature optimization is the root of all evil" - Donald Knuth
From the documentation:
By default, a Double value contains 15
decimal digits of precision, although
a maximum of 17 digits is maintained
internally.
I suspect that you're running into precision limits. Your value of 999,999,999,999,998 probably is at the limit of precision. And since the ulong has to be converted to double before calling Math.Log10, you see this error.
Other answers have posted why this happens.
Here is an example of a fairly quick way to determine the "length" of an integer (some cases excluded). This by itself is not very interesting -- but I include it here because using this method in conjunction with Log10 can get the accuracy "perfect" for the entire range of an unsigned long without requiring a second log invocation.
// the lookup would only be generated once
// and could be a hard-coded array literal
ulong[] lookup = Enumerable.Range(0, 20)
.Select((n) => (ulong)Math.Pow(10, n)).ToArray();
ulong x = 999;
int i = 0;
for (; i < lookup.Length; i++) {
if (lookup[i] > x) {
break;
}
}
// i is length of x "in a base-10 string"
// does not work with "0" or negative numbers
This lookup-table approach can be easily converted to any base. This method should be faster than the iterative divide-by-base approach but profiling is left as an exercise to the reader. (A direct if-then branch broken into "groups" is likely quicker yet, but that's way too much repetitive typing for my tastes.)
Happy coding.