Translate in the bytecode 1e23 into 1 followed by 23 zeros

Who says that floats are represented by 2 integers? Where did you get this idea from?

No, that’s not strange at all. That’s the peep-hole optimizer in action. If the compiler can see an expression that it can work out at compile time, it will.

Use the timeit module from the command line for these kinds of tests.

rosuav@sikorsky:~$ python3 -m timeit 'x = 10**22'
50000000 loops, best of 5: 8.05 nsec per loop
rosuav@sikorsky:~$ python3 -m timeit 'x = 10e22'
50000000 loops, best of 5: 8.22 nsec per loop
rosuav@sikorsky:~$ python3 -m timeit 'x = 100'
50000000 loops, best of 5: 7.92 nsec per loop
rosuav@sikorsky:~$ python3 -m timeit 'x = 100.0'
20000000 loops, best of 5: 7.71 nsec per loop
rosuav@sikorsky:~$ python3 -m timeit 'x = (1, 2, 3, 4, 5, 6)'
50000000 loops, best of 5: 7.87 nsec per loop
rosuav@sikorsky:~$ python3 -m timeit 'x = "Hello, world"'
50000000 loops, best of 5: 7.81 nsec per loop
rosuav@sikorsky:~$ python3 -m timeit 'x = 3+4j'
50000000 loops, best of 5: 7.67 nsec per loop
rosuav@sikorsky:~$ python3 -m timeit 'x = 1+2+3+4+5+6+7+8+9+10'
50000000 loops, best of 5: 8.13 nsec per loop

There is no difference here. Integers are not “so much slower” than floats; all you’re seeing is noise. If we rank these by the times shown here, complex numbers - which really ARE represented with two floats - are faster than floats, and exponential notation is slower than the other forms. But that’s not really what’s going on here, is it? As you found out when you actually looked at the bytecode. This is the same code in all cases.

I wonder if the reason you wanted a different place to post ideas was that you want a place for half-baked ideas where you won’t be criticized for not doing your research before posting?

Ok, let’t remove the noise:

marco@buzz:~/sources/cpython_3_11_build$ python3.11 -m timeit -s "x = 100" "x * x"
10000000 loops, best of 5: 21.6 nsec per loop
marco@buzz:~/sources/cpython_3_11_build$ python3.11 -m timeit -s "x = 100.0" "x * x"
20000000 loops, best of 5: 14.5 nsec per loop

Floats are faster.

PS I agree, people should do better tests and do some good research before posting harsh comments.

Well, it’s the definition of a float… a float is two integers, a mantissa (significand) and an exponent:

(3 if you count the sign, but integers are signed too)

You keep using the word “represented”. I do not think it means what you think it does.

And that is still noise. Here’s a comparison:

rosuav@sikorsky:~$ python3 -m timeit -s "x = 100.0" "pass"
50000000 loops, best of 5: 6.69 nsec per loop
rosuav@sikorsky:~$ python3 -m timeit -s "x = 100" "pass"
50000000 loops, best of 5: 7.42 nsec per loop

rosuav@sikorsky:~$ python3 -m timeit -s "x = 100" "x * x"
10000000 loops, best of 5: 21.7 nsec per loop
rosuav@sikorsky:~$ python3 -m timeit -s "x = 100" "[x, x][0]"
5000000 loops, best of 5: 60.2 nsec per loop

There is a measurable difference with constructing and subscripting a list, but there cannot POSSIBLY be a meaningful difference between a pass statement with an int and a pass statement with a float. Learn to benchmark and learn how insignificant these figures really are.

Chris, I have few time since I’m working and simply my pc is stuck.

Why you tested list subscript for ints and multiplication for floats?

Python does not use Binary32 floats, it uses Binary64 (C doubles).

Both the Binary32 and Binary64 data structures are not “two integers”. The Binary64 data structure has three fields:

  • a single bit representing the sign;
  • 11 bits representing the exponent minus 1023;
  • and 52 bits (plus one virtual or implicit bit) representing the significand or mantissa.

None of them are “integers” in the most common sense of (say) a 16-bit int, 32-bit int, 64-bit int, or BigNum int like Python’s int type.

I accept that the exponent field can be interpreted as an 11-bit biased integer with an offset of 1023. But the significand cannot be interpreted as an integer. It usually represents the “digits” of a base-2 fraction 1.bbbbb…b where each of the b’s are bits from the significand.

Of course we can copy the 64 bits of a Binary64 value into any of these:

  • one 64-bit int;
  • two 32-bit ints;
  • four 16-bit ints;
  • eight 8-bit Latin-1 characters;
  • sixty four 1-bit boolean flags;

etc, but that’s just copying bits. We can do something similar to any data structure.

For example, the float 0.1 can be cast to the 64-bit integer 4591870180066957722, the two 32-bit integers (2576980378, 1069128089), or the 8-char Latin-1 string “\x9a\x99\x99\x99\x99\x99\N{SUPERSCRIPT ONE}?”.

We don’t really think of a float as eight Latin-1 characters, or one/two/four/eight integers. A float is a float. It’s not defined as two integers. Its defined as a float.

You are STILL missing the point. Objects are objects, It will not make the slightest difference whether you are working with integers or floats when all you do is create and subscript a list. It will not make the slightest difference whether you are working with integers or floats when you just pass.

And it makes very VERY little difference even when you multiply them. You might as well “prove” that even numbers are faster than odd numbers for addition:

rosuav@sikorsky:~$ python3 -m timeit -s "x = -3" "x + x"
10000000 loops, best of 5: 20.9 nsec per loop
rosuav@sikorsky:~$ python3 -m timeit -s "x = -2" "x + x"
20000000 loops, best of 5: 14.7 nsec per loop

There actually is something to this, but, spoiler alert, it’s nothing to do with whether they’re odd or even.

Testing random things and showing insignificant differences in timings does NOT prove that some operations are actually faster than others.

Coming back to your performance question:

Operations on floats are (mostly) very thin wrappers around your platform maths library. So x*x when x is a Python float is nearly as fast as your hardware and operating system can multiply two 64-bit Binary64 values, which is pretty fast.

Python ints are BigNums, not fixed size machine ints. Operations on ints don’t directly use the CPU integer operations, but use “BigNum” operations, which are still pretty fast, but not as fast as dealing with fixed width integers.

In particular, 10**22 uses 74 bits, so too big to fit into a standard 16- 32- or 64-bit machine int.

[steve ~]$ python3.10 -m timeit -s "x = 1e22" "x*x"
10000000 loops, best of 5: 23.7 nsec per loop
[steve ~]$ python3.10 -m timeit -s "x = 10**22" "x*x"
5000000 loops, best of 5: 58.6 nsec per loop

Floats are faster.

How much faster is very sensitive to your hardware and the version of Python you are using.

I am running on an AMD micro PC which is very slow compared to other machines, and I think that I’m also running a debug build of Python, which may also slow things down.

Fast machines may not show much difference in speed. Slow machines may show more difference. And if you are running a version of Python with this:

operations on small ints may be as fast or faster than floats.

(But big ints will be slower.)

But I tested also 100 and it’s slower than 100.0.

So probably this is the problem. Python floats are not BigNumbers:

>>> 1e308
>>> 1e309
>>> 10 ** 1000
>>> 10 ** 10000
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Exceeds the limit (4300 digits) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit

It seems that there’s a limit for floats, while integers are only limited in the display, that you can rise until your memory is full.

I never wanted to test lists. Please read the discussion between me and Stephen. And please reply to Stephen, if you can.

They might not even be measurably slower, depending on how well it’s implemented. And since the vast majority of programs spend the vast majority of their time working with numbers that fit into a machine word, this should produce an overall improvement in performance.

I’ve advocated for this kind of “invisible optimization” in ints for quite a while. There are other languages that work this way, and it makes integer operations simultaneously convenient (no boundary between int and long) and, at least for the common cases, performant.

(Pike actually goes further: small integers are actually stored unboxed. If the low bit of a “pointer” is set, it’s actually an integer using the other 31 or 63 bits, with the actual integer object being completely implicit. CPython probably can’t achieve this due to the issues it would cause for extension modules, but it does make for some pretty sweet memory savings.)

If you didn’t already know this, then I strongly suggest you should be doing more research before posting. Otherwise, you’re wasting everybody’s time, first by misunderstanding their responses as a result of your lack of background knowledge, and second by needing people to explain basics to you.

Can I remind you that discussions here need to take into the account the principle of respecting other people’s time and effort? It’s not reasonable to simply come along with a half-formed idea that you haven’t done the basic background research into.

1 Like

I suppose you understood.

I believe micropython does this (unboxed integers) as well – though I’m working from an old memory, I can’t find it in the docs right now, so my memory may be faulty, ot it could have changed.

It’s not a matter of boxing. Floats are boxed too. Don’t follow the noise.

Paul, if you feel your time with me is wasted, I suggest you to use the forum ability to snooze this thread.

The fact you say I misunderstood something is very generic and subjective. Can you give me an example when I misunderstood a response?

If the fact that integers have arbitrary precision in Python and this leads to slowdown in integer arithmetic is a “basic” knowledge, sorry, I think my mom should have taught to me when I was 4 :smiley:

That would make good sense for uPy. There’s nothing in the Python language that precludes it, as long as the id of an integer can be easily defined (for example, if id(x)==x). It’s semantically equivalent to the CPython “small integer cache” but expanded to a much larger range of values.