-
Notifications
You must be signed in to change notification settings - Fork 283
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
PEP 237 -- int/long Unification #52
Comments
On modern 64 bit machines, we could use Int64 instead of Int32 for "simple" operations. (Or just use 64 bit on all platforms, assuming emulated Int64 is still more performant than BigInteger... ) This is also what Python 2 did on 64 bit machines, as I just verified on an older ubuntu installation:
|
To get a feeling about performance of various options across frameworks, I have done some measurements of a few arithmetic operations executed in a long loop. Results of all operations fit in 32 bits so it is possible to compare to native .NET Performance ResultsHere are best times for various types used for the variables in the loop, for both checked and unchecked code, on AMD Ryzen Threadripper 3960X. Test loop template in C# public void CheckedIntTest()
{
int n = int.MaxValue;
int z = 0;
checked
{
for (int i = 0; i < n; i++)
{
if (i % 2 == 0)
{
z += i;
}
else
{
z -= i;
}
}
}
}
Comments: [1]: The above is just the performance of raw .NET. It is useful to see the the relative cost of IronPython/CPython Performance ResultsI have rewritten the test code above in Python and run it under various Python interpreters. Here are the results on the same workstation. Test loop template in Pythondef int_test():
n = 0x7FFFFFFF
z = 0
i = 0
while i < n:
if i % 2 == 0:
z += i
else:
z -= i
i += 1
return z
[1]: CPython test runs with GC disabled. It is interesting to notice that, thanks to using Of course there is more in the test going on than just simple integer arithmetics: comparisons, jumps, variable assignment, etc. This is deliberate. I wanted to get an impression of performance of an "average" Python code doing some basic arithmetics and the relative cost of the switch for programs at large. Below are test results focused only on the performance of a single arithmetic operation. Test Codeimport timeit
timeit.timeit("z = a * b", setup="a=3; b=4", number=1000000000)
[1]: CPython test runs with GC disabled. The overall picture is the same as in the previous test. ConclusionsIt seems to me that adopting So my recommendation is to go ahead with modifying IronPython in a way that both What about using
|
Considering the dominance of Int32 in .NET APIs, I agree that getting Int64 "on board" may not be worth the effort, and it can still be implemented later. |
I was leaning towards something of the sort as well. Did you have an approach in mind? I guess a hacky way could be to just hide it by having |
I was thinking of keeping On a side note, I was surprised to discover that currently
I like your idea better than mine because it seems to require only one hack. Support for debugging can be done by adding an IronPython-specific dunder property to the type (say,
I thought that we could merge I have envisioned one more change: abolishing the usage of class SubInt(int): pass
SubInt(1<<64) # OverflowError There are a number of places that test if the the argument is, among other possibilities, |
I'm special casing it. See #858.
I'm not sure, I briefly looked into it before suggesting and there seemed to be a special call site for ironpython3/Src/IronPython/Runtime/Types/PythonType.Generated.cs Lines 94 to 100 in a8d1454
Yes and no. I'm not too worried about import clr
clr.AddReference("System.Numerics")
import System.Numerics.BigInteger
print(set(dir(1<<64)) - set(dir(1)))
print(set(dir(1)) - set(dir(1<<64))) Although most of those appear to be static properties on
This is interesting. Probably a good idea from a compat point of view. |
Thanks for the pointer. I assume this special case can be removed after the unification is completed.
OK, it settles it then. Just to make sure we are on the same page: both
I see. Although most of those appear to be methods on IronPython 3.4.0a1 (3.4.0.0001)
[.NETCoreApp,Version=v3.1 on .NET Core 3.1.22 (64-bit)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import clr
>>> clr.AddReference("System.Numerics")
>>> import System.Numerics.BigInteger
>>> print(set(dir(1<<64)) - set(dir(1)))
{'GetWords', 'ToChar', 'Divide', 'Xor', 'BitwiseOr', 'Remainder', 'ToDouble', 'Abs', 'Min', 'IsZero', 'AsUInt64', 'ToSingle', 'TryWriteBytes', 'ToUInt64', 'AsInt32', 'GetBitCount', 'GetWord', 'IsEven', 'ExclusiveOr', 'GetWordCount', 'BitwiseAnd', 'AsDecimal', 'IsPowerOfTwo', 'Compare', 'IsOne', 'ToInt64', 'Add', 'MinusOne', '__complex__', 'IsNegative', 'One', 'LeftShift', 'GetByteCount', 'Log', 'ToSByte', 'ToUInt16', 'ToUInt32', 'ToBoolean', 'Pow', 'ToType', 'ToByte', 'AsInt64', 'Zero', 'RightShift', 'ToFloat', 'Negate', 'OnesComplement', 'ToInt16', 'GreatestCommonDivisor', 'Multiply', 'Sign', 'DivRem', 'ToByteArray', 'Subtract', 'Mod', 'IsPositive', 'ToDecimal', 'Square', 'Log10', 'ModPow', 'ToInt32', 'AsUInt32', 'Create', 'Max'} I'm not too worried about it. Most are redundant but we may still add the missing ones to |
Not sure if we'll be able to get rid of it, it might just change to
Hmm, interesting, hadn't though about what the "real" backing |
That was one of the motivations. Another was to make
Exactly. This will make the type |
There is one more place where a hack is required: Currently both functions are identical in functionality (one calls the other). I propose to add the hack in The new code: internal static string GetPythonTypeName(object? obj) {
if (obj is int) return "int";
return PythonTypeOps.GetName(obj);
} @slozier, are you OK with that? I am asking in advance because currently half the calls in the codebase are to the first function and the other half to the second. So after the change I will have to change 99+ places to use The alternative is to place the hack at the lower level in |
@BCSharp This one is interesting. I've been wanting to normalize the "get type name" throughout the codebase so I'm fine with picking one call site and doing it. Also probably a good idea to have an analyzer to discourage the use of the other patterns. Another pattern to watch out for is Since this is going to be hitting a lot of code might be a good idea to have a PR specifically for this - will make reviewing easier. |
Python 3 gets rid of the distinction between int and long, with int now behaving as long. One way would be to switch everything to BigInteger, but it might be more efficient to try and use Int32 as much as possible behind the scenes, and switch to BigInteger if we have to while keeping the visible type int at all times.
Probably worth doing some benchmarks to see if it's worthwhile first.
The text was updated successfully, but these errors were encountered: