Decimal, double, int, long which one is the biggest positive number?

I’m reading the docs about big numbers

Seems that decimal is the biggest one, is it correct or wrong?

If I have a number 4E+168, which type of number should I use?

And the most “weird” for me, doesn’t matter which type of number I use, I can use only 19 zeros, anything above 19 zeros will popup a mistake “Integral constant is too large”

// 19 zeros
double num = 10000000000000000000;

Thank you in advance

What is the number used for?

First of all, be aware that the specified range for non-integer types does not mean that you can represent all the numbers in between. At some point, you cannot even represent all the integers anymore even though the specified range appears to tell a different story. That’s how floating point numbers (no matter if 8bit, 16bit, 32bit a.k.a float, 64 a.k.a double, 128 a.k.a decimal in C#) work.
(Just saying in case you want to do serious math with such big numbers.)

It all comes down to how the numbers are represented in binary with respect to their specification. For such types, there can even be different specifications (perhaps take a look at commonly used IEEE specifications).

It would take a rather long post and also some knowledge about the details of the specifications, personally I don’t feel confident enough in that topic to dive deep into it without possibly spreading false information or getting myself and others confused.

However, the numerical limit you experience with your current code snippet has a different reason. The literal constant you typed in is implicity interpreted as an integer, more specifically as an unsigned integer with 64-bits, a.k.a ulong (System.UInt64).
Since the maximum value that can be stored in a unsigned 64-bit integer is (2^64)-1 = 18446744073709551615, you’re getting the error when adding more digits to the literal. Even if you incremented that literal by 1, it’d be marked as an error because it’s still being understood as a literal of type ulong, and thus exceeds the type’s range.

If you explicitly declared the literal as a double instead, i.e. 18446744073709551615**.0**, you’d be able to go much higher. Technically you always run into the risk of loosing precision that you might need, but the smart way of storing floating point numbers in memory is pretty flexible, hence the enormous range.

With regards to the decimal type, memory-wise it’s indeed larger than a double since it’s designed to use 128bit. But it’s not stored with a base of 2, but 10 instead. This type enables you to deal with very, very high precision, like it is required when dealing with money for example. You cannot go as high, but you’re almost resistant to having serious precision errors that might accumulate over multiple operations.

Last but not least - and like mentioned earlier - you can actually store the value

double d = 4E+168;

Keep in mind that accuracy can be a serious problem, depending on which sort of numbers and precision you have to deal with.

2 Likes

It’s the highest price of item, I’m trying to do some idle clicker for better unity learning

If I don’t need accuracy then I can manipulate double in that way?

That’s a huge price. Is the price going to be 1PriceUnit = 1 click?
If that’s the case, you could do some math and figure out what’s a reasonable maximum price for your specific game. Actually, you can do that for any price unit / n clicks.

Perhaps that value is far out of range.

I’m not entirely sure. You could simply try and do some math and see how it turns out.

There are also other ways of solving this problem.

You could (for instance) scale the values, but this solution only applies if you’re close to the range of an integer value or close to an acceptable precision of floating point values:
Let’s say you have prices that start at 10000 clicks, and you never use the digits that represent 0-9999, that is, your price list contains values that could be divided (based on integer math) by 10000 without any loss of information.
You could then start with a price of 1, while the UI prints it with 5 additional zeros.

=> I doubt this is a solution to your problem, regarding the huge number you told us about.

Next would be your own wrapper type that stores multiple integers.
I won’t bother explaining this solution, as there is already an implementation available (since .NET 4). If you configure your project to use the 4.x API compatibility and runtime, you can take a look at the System.Numeric.BigInteger type.

Yes, I guess it will be one click purchase, but it’s the most expensive item.

Thank you a lot for your efforts trying to solve the issue.

Oh okay, but well… You should actually do the math in this case.

4E+168 is 4 *10^168, a number that consists of a 4 with 168 zeros, that’s an incredibly huge number.

In comparison, the estimated age of the universe is something around 14 billion years, i.e. ~ 5.11E+12 days if you calculated the number of days using our time system.
Say your game allowed to get 10.000.000.000 (10 billion) clicks a day (116.000 “clicks” a seconds), that timespan could represent 5.11E+22 clicks, whereas the price for the most expensive item required 4E+158 days or roughly 1.1E+156 years to be reached.

Oh, you mean this number is unreachable? Actually it’s not “my” number. There is a game which I try to re-create. It’s the best way to learn when you see the sample and try to follow and do yourself.

Well yep, that’s the short version.

I think the major problem or confusion appears to be the exponent…

If you were to write a program with a trivial counter that counts up to that number, it’d take an incredible time to finish.
Assume your progam was able to increment the counter 10 billion times a second (which is fairly performant), it would take a whole day to reach 864000000000000, a week to reach 6048000000000000, a year to reach 315360000000000000.

That’s roughly 3.1510^17.
After 10 years, that counter would reach 3.15
10^18, a number that only differs by +1 in the exponent.

In 10.000 years, that program would reach 3.15*10^21. Just a small fraction of the number you aimed for.

Some other comparisons (all the numbers are taken from the web):
Earth consists of ~ 10^50 atoms.
An estimate of the atoms in the “visible” universe is ~10^80.

Keep in mind that the number you show to the user doesn’t necessarily have to be the same as the number you store in code.

For instance, suppose you always give out money in multiples of a million dollars. One simple action gives a million dollars. A bigger payoff might be 27 million dollars. But it’s always going to be a multiple of a million.

Instead of storing the user’s money internally as int money = 1000000 you could store it as int money = 1 and then append six zeroes when you display it on the screen.

currentMoney.text = money + “000000”;

This way you don’t need as large a data type as you otherwise might need.

I managed to find one interesting solution double.Parse("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")

And I will have 1E+189 in game. I guess more zeros will work as well. What experts of C# can comment on such approach?

But of course I can reduce zeros, since I don’t need accuracy, solution offered by Antistone.

I wouldn’t use the builtin data types for solutions they were never intended to be used for. I would use a BigInteger library like the one linked below which supports 3,000 decimal digits.

https://www.codeproject.com/Articles/60108/BigInteger-Library

Can I parse bigInteger from string for example?

So why would you want to do that instead of actually using double numbers? If you need to read the values from somewhere, consider using serialization instead.

The above does only make sense when you read unknown strings from some source of input, such as user input fields.

That’s what I mentioned earlier, but as stated in my post, it won’t help you unless you start at 10^100 or even higher with the lowest price, because you’ll still need to cover a range of values which are within 0 and 10^68 (with your orignal value). With your new value 10^189, you’ll even need to start much higher.

The conclusion is that you scale down the whole price system to something that’s 1) reasonable 2) reachable 3) easy to implement.

And if you still want to use these frustating high values, use either of the following:

2 Likes