-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
[API Proposal]: Support General Math value creation without sign propagation #106927
Comments
If you need a delta between two numbers, use |
I need to get TTo(255) from TFrom(-1). Abs(-1) is equal to 1 but not 255. |
This isn't valid given an arbitrary Given If all values are within range of |
Can you provide a more concrete example and explicitly lay out the constraints/assumptions of What you'd want to do if It also differs based on whether |
Yes When For example when |
This doesn't sound correct, as you could have a negative result produced for the scenario I gave, such as The only case it would be safe is if you knew that
When you have negatives covering the full range like this, there isn't really any fix you can do. You have lost information the moment you did You can't use the For types with a representable range smaller than |
Yes
I don't know in advance when
It works for |
I propose to expand the API for this case so that it always works. |
Which means its not an API we can provide in box.
This would be a breaking change and is not something we're interested in doing.
If you can guarantee that length = int.CreateTruncating(end - start);
if (length < 0)
{
length = int.CreateTruncating(end) - int.CreateTruncating(start);
} |
No breaking change in my suggestion. |
The breaking change is that we cannot provide such a DIM without requiring some behavioral breaking change due to the fact that the output of Such as for There's no API we could provide here because there is no way to do the conversion and have it always behave as you're intending. |
@tannergooding I didn't look at how |
There are two This ensures that some concrete type is always defining the correct conversion behavior, because it at least understands its own definition and that is enough to ensure correct deterministic behavior in most scenarios. The number types were designed to work by understanding the exact represented value of a |
@tannergooding As far as I understood your explanation, the proposed API can be implemented. I'm not suggesting using serialization. |
You're going to have to give the code you believe will work here. I do not see a way that a |
@tannergooding Assert.Equal(unchecked((int)0xFFFFFF80), NumberBaseHelper<int>.CreateTruncating<sbyte>(unchecked((sbyte)0x80), true));
Assert.Equal(unchecked((int)0xFFFFFFFF), NumberBaseHelper<int>.CreateTruncating<sbyte>(unchecked((sbyte)0xFF), true));
Assert.Equal(unchecked((int)0x80), NumberBaseHelper<int>.CreateTruncating<sbyte>(unchecked((sbyte)0x80), false));
Assert.Equal(unchecked((int)0xFF), NumberBaseHelper<int>.CreateTruncating<sbyte>(unchecked((sbyte)0xFF), false)); runtime/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.GenericMath.cs Lines 1980 to 1999 in 47c68c6
|
@AlexRadch, I think you misunderstood. I meant a generic DIM implementation, not a per type specialized implementation. This would require a DIM and therefore a valid default implementation would need to be provided, which I don't believe is possible here. |
I don't understand why we need to make a generic DIM implementation of the new |
You cannot expose new methods on existing interfaces without giving them a default implementation, that is a breaking change otherwise. The It is likewise not sufficient to introduce APIs which fail for all types by default. This is a pit of failure for users. The behavior you're wanting here rather seems something that is specific to two's complement representation and bit-blitting of data between types, not something that is truly general purpose and works for all numeric types. I do not think it is a good fit for the generic APIs. |
I wrote a default implementation, otherwise nothing would have compiled for me. runtime/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs Lines 411 to 421 in 47c68c6
runtime/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs Lines 460 to 470 in 47c68c6
|
That implementation fails for common inputs and will result in the public For example, The expectation is that by default:
This is what I believe cannot be trivially achieved through a DIM and which is largely relying on very particular semantics of two's complement fixed-width primitive integer types, not something which is more general-purpose/generic in nature and which is a good fit for arbitrary number types. |
For base types, the new After all, even now there is no correct general slow implementation of the old I don't understand why the old Where does this demand come from? |
These were introduced day 1 and do not have DIMs, it is required for all types to implement them so there is no risk of existing types not supporting such an API. Now that the types have shipped, new members must have DIMs to avoid being a binary breaking change. That DIM needs to be sensible and function as users would roughly expect across all types. A given type can then explicitly provide their own more efficient implementation, but that should namely be for performance or precision not for general correctness. |
Ok. I think I can use |
This issue has been marked |
Background and motivation
I want to calculate the difference between two values as a non-negative
max - start
number.TFrom start
, andTFrom max
define a range whose length is from0
toint.MaxValue - 1
.0 <= length < int.MaxValue
When
TFrom
is wider thanint
, calculate the length simply aslength = int.CreateTruncating(end - start)
, because the differenceend - start
is always positive.When
TFrom
is narrower thanint
and has a sign, the difference between them can be a negative number, which is difficult to convert to a positive value. For example whenTFrom
issbyte
andstart = -128; max = 127
thenlength = 128 + 127 = 255 = -1 (signed byte)
.It isn't not easy to convert TFrom(-1) to positive TTo(255)
int.CreateTruncating(TFrom(-1))
creates int(-1)uint.CreateTruncating(TFrom(-1))
creates uint.MaxValue. This made the sign propagation!So I made the next workaround code.
API Proposal
API Usage
See also
runtime/src/libraries/System.Linq/src/System/Linq/Range.cs
Lines 30 to 49 in e689e2a
Alternative Designs
No response
Risks
No response
The text was updated successfully, but these errors were encountered: