New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Standardized Rational object #21588
Comments
My comments:
|
@svick Thanks 1 - I just thinking that for fraction value. We use 2 - There are 3 - I have research it and think that it's true. That struct should be named 4 - You are right. That expression would need more work to do. I would thinking more about it |
@svick is easy one |
I have seen Rational types used in libraries before, but they are usually very niche (for example), and in my opinion aren't very interesting for us to include in the BCL. There are all sorts of different specialized mathematical types we could potentially include, but we only want to include things that are generally or universally useful. I feel that this would be better served by a third-party library for the time being. |
@mellinoe I think it's niche because we actually not included in BCL All of financial and statistics application or even graphics and physics simulation could replace most floating point in the code into rational if it was standard library But because it not standard no one would likely risk downloading additional library for their crucial job so it still neglect even it make calculation more accurate. They need to bear with float because float is standard This is somehow dilemma. I think it need to start somewhere to make it being general But I think |
Certainly, that is always a possibility. However, this isn't just a niche type in C#/.NET. I'm not really aware of any graphics or physics libraries which represent data in this way, even in other languages. IMO, it's also more than just being inconvenient or poorly-supported in libraries. GPU's fundamentally don't understand this data format. Real-time physics simulation libraries still predominantly use 32-bit floats for speed, even though 64-bit floats would be essentially a drop-in replacement. A rational structure wouldn't be. I'm not saying that this wouldn't be a useful type, I'm just not sure that it is universal enough for inclusion in the BCL, at least not yet. I agree with @tannergooding's suggestion in the other issue that this would be great to build as a standalone NuGet package before consideration for the BCL. |
@mellinoe As I said it hardly compared because both float32 and float64 was standardize into bcl. You don't need to rely on nuget Actually it was ingrained into literal It like C# that even it better than Java, it still struggle to raise the popularity than Java. Because Java was born before I bet if We might gone too far now. floating point was being standard for so long even before GPU itself. And in the old day computer was limit by many cap, a floating point that can represent widely range of number would be more useful to support it than rational number But nowaday we have ram in GB unit. I think we should start solving bug |
@Thaina. I don't think you'll ever see float drop away as the primary representation for values. As @mellinoe points out, there are no major real-time libraries that use anything other than float, primarily because they care more about speed then they do precision. When you are manipulating 2073600 pixels (that's 1920x1080) 60 times each second (and it could be more with 4k resolution and higher refresh rates, which are becoming more common) to provide a smooth but realistic enough experience, you want speed and that is something that raw integer math can't handle (even when representing a rational number using a numerator/denominator pair). The primary reason that integer math doesn't work is because there isn't hardware to support it. Graphics cards are essentially tens or hundreds (sometimes thousands) of compute units designed specifically to crunch floating point numbers. Even on the CPU, floating point throughput can be higher than integer throughput, because the pipeline has been specifically designed to handle it and to handle it seperately from normal integer operations. For example, the Intel Haswell, Broadwell, and Skylake processors can retire a maximum of 32 single precision operations per cycle (when doing two 8-wide FMA instructions). Now, you appear to be wanting to solve some of the common and well known problems that arise from floating-point arithmetic and many of these are already solved (and standardized). The primary issue with binary floating-point arithmetic is that some numbers are not exact. For example, the following program: var value = 0.0;
for (int i = 0; i <= 10; i++)
{
Console.WriteLine($"{value:G17}");
value += 0.1;
} Produces:
This issue, however, only exits in "binary" based floating-point arithmetic. IEEE also defines "decimal" based arithmetic which does not suffer from most of these problems (I don't think our For example, the following program: var value = 0.0m;
for (int i = 0; i <= 10; i++)
{
Console.WriteLine($"{value}");
value += 0.1m;
} Produces:
Applications which require more precise results (such as financial applications) will use the decimal based arithmetic over float/double (which are binary based arithmetic). The program takes longer to run, but will give the more precise results that they need. Decimal based arithmetic does still have some shortcomings. For example, 1/3 is represented as Then there are applications which require even more precise results (such as scientific applications that are performing data modelling or making extremely precise measurements). For the cases where even decimal doesn't meet their needs, they will end up rolling their own (or using some existing library) that does take care of their needs so that they can precisely compute/model all numbers (rational numbers, irrational numbers, complex numbers, trascedental numbers, etc...). |
I would like to add my voice to support this proposal. Rationals are actually incredibly useful for a wide variety of applications (for example, doing arithmetic with currency in a manner that is guaranteed to be accurate). In many cases where people use IEEE754 floats, rationals can be dramatically better. I would like to suggest a few things though. First of all, just a stylistic thing, can we please use the terms Second, a normalize method will be necessary to simplify a rational to its normal form. This may signal the need for two Rational types at least (one which enforces normalization after each operation) and one which does not. I'm not sure which I would prefer, though I suspect we might want to have the routine always called in Third, in an attempt to avoid adding a whole class of exceptions and silly behavior, the fields should really be Fourth, if it is preferred, a rational type can reasonably be defined as an encoding of a single integer as having two parts (and a separate field to track where the separator is). A I can provide an example |
Just a quick note that there's a rudimentary Rational class from the old bcl codeplex site @ https://github.com/MicrosoftArchive/bcl/blob/master/Libraries/BigRational/BigRationalLibrary/BigRational.cs @HalosGhost if you're passionate about working on a prototype or example Rational type for .NET Core, a repo for the experiment to happen in could be https://github.com/dotnet/corefxlab However I do think Rational isn't really suitable for many basic scenarios (that are better supported by existing decimal or double types); the folks that do need a Rational type are likely working on advanced mathematical modeling / simulations / solvers - and have domain specific requirements that would need to be met in order for the type to be usable by them. /cc @eerhardt |
Excuse me for being a year+ late, but was anything decided on a big rational? Nearly all these threads I read seem to die off and not lead anywhere. Thanks in advance! @HalosGhost @joshfree |
@carlyman77, I have a functional prototype lying around, but I got stuck on deciding how to handle canonicalization. Namely, whether or not a Rational should automatically canonicalize anytime you do anything with it, or if it should instead only be canonicalized during comparisons. there's not necessarily a down-side to the latter, and it saves a fair bit of computational power. Thoughts? |
That's a good question. I think during comparison sounds reasonable. (Thanks for responding to me btw, it sounds like you are way in front of where I am - considering writing my own rational.) There are use cases where accuracy is far more important than performance (my physics project for example), although as @joshfree points out these use cases might be limited (read: not commercial). |
Just my 2 cents. Every project where I've needed this has required the canonical form, so I'd lean towards always canonicalizing (and maybe for fun, you could also keep the original raw BigInteger numerator and denominator values as separate properties). Another option is to provide a global static flag that determines the canonicalization behavior. Default it to always canonicalize, but the user can set it to false so that it only canonicalizes when required or explicitly requested. |
PS - If you do implement this, please implement it as BigRational (based on BigInteger) rather than the other integer types. Rationals that don't have arbitrary precision quickly become useless, as most applications that would use them require perfect precision, and most calculations involving them create large numerators and denominators that exceed the precision of the non-BigInteger types. |
Even though I request this feature myself but for such times I have a new idea already but it still not solid I now think we should not have a struct for rational. Instead we should have class for Number and it's exponent. Represent rational with negative exponent, Then we could represent the number by the array of product
Not sure is better or worse |
I can see use cases for this, but I also see many use cases for a standardized arbitrary-precision rational structure. I don't necessarily see it as either/or. For me personally, a rational object would be more useful, but I could see this being useful in some cases too. |
If implemented, a
I don't like the idea of a global flag as they are tricky and can easily introduce bugs. I'd rather instead say that we follow what IEEE 754 does for its |
Indeed. Since the thread is called "Standardized Rational object" and much of the discussion left the nature of the proposed standardized rational object ambiguous, I just wanted to state explicitly that I think an arbitrary-precision
Totally fair. I'd lean toward canonical results by default because the canonical form is needed for most uses. At the very least, I would cache the canonical form once computed so that you wouldn't need to calculate it more than once for any given |
The next step here would be for someone to propose the public surface area of the
Other operators (such as ^, &, |, <<, and >>) would likely need to be discussed, but I don't think there is a reasonable implementation. Implicit/explicit conversions for the integer and floating-point primitives would likely need to be discussed (and decided if those or constructors are better). After that is done, we can likely have a discussion around class vs struct and the proposed API can then be taken forward to API review. The API review process is detailed here: https://github.com/dotnet/runtime/blob/master/docs/project/api-review-process.md, with a "good example" listed under step 1. Not all parts from the good example area required, but providing some basic rationale and the proposed API section are good minimums as they help centralize the proposal and avoid needing to help scrolling around the tracking issue. |
Happy to start looking into the shape that the type would take (assuming my 1 year old cuts me a bit of slack in the coming days). FWIW, I prefer the name Rational over BigRational. The initial design I was thinking of working towards was using bit strings until I found a better way to do it. Edit: invites incoming for collaborators, please ping me if you're keen. |
NOW there is a new momentum with INumbery. There is even a chance to implement rational / fraction based on a template Integer type. Rational where T: and also make Rational itself implement INumber (or maybe only partially). Having this a part of the standard library would encourage way more people to use it. The existing NuGet packages are just not enough supported. |
Someone will need to write a full proposal covering the entire proposed API surface for a I am not against providing such a type in the Edit: I'll try to do the proposal myself, if no one else gets to it first, sometime after we lock down for .NET 7 RC1 |
@ALL, I would like propose a new solution for a rational number type and arbitrary arithmetic in general for NET7 System.Numerics. |
This issue was ported from dotnet/csharplang#553
Lately in csharplang whenever we talk about struct feature. Rational struct often came up as an example
And so I think that Rational actually useful. Normally approximate number with float.
3 * (1 / 3f)
is not became what we would expect. Floating point error need to be handled everywhere since we program in CMost of the time we care about precision than the range of number. If we could naturally use
Rational
in code it could make a lot of sense in many calculation logicAnd instead of always making Rational on our own then overriding all operators just about conversion between each number type. I think it could be useful enough to have it built in
ps
We actually could handle internal value like this
With this we will always handle negative only in number. And zeromemory will be
0 / 1
ps2
Should we also add
Irrational
andAlgebraic
object too?I think most of calculation we use in graphics and physics simulation could be use
Irrational128
in generalps3
From csharplang repo I was propose this feature to have literal syntax. And there are suggestion that it should at least make the object itself pass corefx first
The text was updated successfully, but these errors were encountered: