AdamWhiteHat / BigDecimal

An arbitrary-precision decimal (base 10) floating-point number class.
MIT License
47 stars 15 forks source link

BigDecimal.Precision have no effect #46

Closed theuserbl closed 4 months ago

theuserbl commented 4 months ago

I testet you example code. There I have only changed a "." to an "," , because in europe point and comma are switched. Without changing point to comma, the error looks like

BigDecimal01

But the precision of the number is a higher precision then yours. Seems to be 372 instead of the setted 200, because the Mantisse is 372 characters long.

BigDecimal02
AdamWhiteHat commented 4 months ago

Set the static member: BigDecimal.AlwaysTruncate = true;

This will constrain the number of digits to the right of the decimal separator to the value specified in BigDecimal.Precision. Well, to within +/- 1 digit of the precision, anyways.

With BigDecimal.AlwaysTruncate set to true, it will truncate the BigDecimal after every arithmetic operation.

With BigDecimal.AlwaysTruncate set to false, it will never truncate the numbers on its own. The user is in control of when, if ever, the number should be truncated, by calling the Truncate method manually; Usually after a series of operations, but before returning/presenting the final result would be a common place to do so With BigDecimal.AlwaysTruncate set to false, any newly constructed BigDecimal begins its life with up to Precision digits in length (if needed. 1/4 is still going to be just 0.25), and any arithmetic operations that results in a longer decimal representation (e.g. multiplication) will result in a longer decimal representation.

The default value for BigDecimal.AlwaysTruncate is false.

I figured its better to keep the trailing digits by default, requiring the behavior that throws them away be set explicitly, than to toss away digits of precision to peoples' calculations by default, requiring that keeping the full precision be made explicit.

This all should be reflected in the readme. If its not, I will add it at once.

I should also probably state this in the readme, if it isn't already:

Setting BigDecimal.AlwaysTruncate = true; may significantly boost performance. If you are finding your calculations are taking a long time to return, and you find that your intermediate values have decimal representations that have grown obscenely long, setting BigDecimal.AlwaysTruncate = true; should see immediate gains in speed at the cost of a little precision.

AdamWhiteHat commented 4 months ago

I perhaps misunderstood what you were saying.

You also seem to be saying that parsing numbers is failing, if you use a comma as a decimal separator.

All you have to do to make that work is set the CurrentCulture to your current culture, or any culture who has the same number formatting rules as yours. Argentina , for example, also uses commas as decimal separators, and periods to group digits to the left of the decimal separator, into groups of three, so we will use that as an example:

CultureInfo argentina = CultureInfo.GetCultureInfoByIetfLanguageTag("es-AR");
CultureInfo.CurrentCulture = argentina ;

When parsing, the library uses the properties of CultureInfo.CurrentCulture.NumberFormat to parse a string into a BigDecimal, so it should do the right thing if you just set CultureInfo.CurrentCulture.

This affects only the thread that runs such a statement. If your application is multi-threaded, consider setting DefaultThreadCurrentCulture instead.

theuserbl commented 4 months ago

Set the static member: BigDecimal.AlwaysTruncate = true;

Ok. I have added the line to the top of your example.

Now it is less precision then before, but the result is still different to your output:

BigDecimal03

You also seem to be saying that parsing numbers is failing, if you use a comma as a decimal separator. All you have to do to make that work is set the CurrentCulture to your current culture,

I am not sure, if it is better, that every program which using BigDecimal, integrating the part with CurrentCulture or if it is better, if BigDecimal itself includes the part with "CurrentCulture", so that a string with decimal-point can everytime in every country direct converted to a BigDecimal.

Currently in Windows it is so, that in cultures, which using a comma in Floating point numbers, the point (".") will be used in programs for numbers and the comma (",") is in numbers, that are outputted to command line.

And for example in the Powershell ist is so, that I input 14.8 + 17.4 and it outputs 32,2

Thats the Microsoft-way. Java and Python don't using comma. They input and output numbers with point.

AdamWhiteHat commented 4 months ago

but the result is still different to your output:

I'm not understanding the issue here... Is it that the the second time it displays that long number, it doesn't have a decimal point in it? e.g. "64079000015605783843835009599722600 ..." ?

If so, well that's because its literally displaying the Mantissa and the exponent:

Console.WriteLine($"{almostInteger.Mantissa}");
// 64079000015605783843835009599722600391518338454771405992063505171997949372951472701529422358634915404757740005027416333594519349348824890921372720968246769717009339797514969003242216358994087504831741
Console.WriteLine($"{almostInteger.Exponent}");
// -193

If you were expecting each line to be output twice, that's not necessarily what its doing or meant to happen. The code comments are supposed to reflect what's output by the console. But the code comments themselves don't print out to the console, so they are tough to compare. But they were not designed to compare. The code in the readme wasn't meant to be a test; it was meant to give people an example of what using the library would look like, and give them an idea what the output would look like. You could use it for a test. If you wrap every code comment with a Console.WriteLine call, you do see two identical lines of output for calculated object:

Console.WriteLine($"{BigDecimal.Precision}");
Console.WriteLine($"5000");
BigDecimal.Precision = 200; // Tone down the precision for this demo.
Console.WriteLine($"{BigDecimal.Precision}");
Console.WriteLine($"200");

BigDecimal goldenRatio = BigDecimal.Divide(BigDecimal.Add(BigDecimal.One, BigDecimal.Pow(5d, 0.5d)), BigDecimal.Parse("2"));
BigDecimal almostInteger = BigDecimal.Pow(goldenRatio, 23);
Console.WriteLine($"{almostInteger}");
Console.WriteLine($"64079.000015605783843835009599722600391518338454771405992063505171997949372951472701529422358634915404757740005027416333594519349348824890921372720968246769717009339797514969003242216358994087504831741");

Console.WriteLine($"{almostInteger.Mantissa}");
Console.WriteLine($"64079000015605783843835009599722600391518338454771405992063505171997949372951472701529422358634915404757740005027416333594519349348824890921372720968246769717009339797514969003242216358994087504831741");
Console.WriteLine($"{almostInteger.Exponent}");
Console.WriteLine($"-193");

BigDecimal X = BigDecimal.Parse("0.000551876379690949227373068432671081677704194260485651214128035320088300220750");
Console.WriteLine($"{X}");
Console.WriteLine($"0.00055187637969094922737306843267108167770419426048565121412803532008830022075");

BigDecimal result = BigDecimal.Divide(BigDecimal.One, X);
Console.WriteLine($"{result}");
Console.WriteLine("1812.000000000000000000000000000000000000000000000000000000000000000000000001");

If you want tests, there is a whole test project with 135 tests.

theuserbl commented 4 months ago

If you were expecting each line to be output twice, that's not necessarily what its doing or meant to happen. The code comments are supposed to reflect what's output by the console.

I know it. But the result is different to that what you have written in the comments.

And here the output of your now published program:

BigDecimal04

-368 ist NOT the same like -193.

And the number "1812,000000000000000000000000000000000000000000000000000000000000000000000001812000000000000000000000000000000000000000000000000000000000000000000000001812000000000000000000000000000000000000000000000000000000000000000000000001" have NOT the same precision like "1812.000000000000000000000000000000000000000000000000000000000000000000000001"

theuserbl commented 4 months ago

Oh, and here, where I added a BigDecimal.AlwaysTruncate = true; at the top of your program.

BigDecimal05

But again, -200 ist NOT the same like -193.

And "1812,000000000000000000000000000000000000000000000000000000000000000000000001812000000000000000000000000000000000000000000000000000000000000000000000001812" have not the same precision like "1812.000000000000000000000000000000000000000000000000000000000000000000000001"

AdamWhiteHat commented 4 months ago

-368 ist NOT the same like -193

Fair enough. Ill update the Readme to reflect the true, correct value.

AdamWhiteHat commented 4 months ago

It it so.