3

I'd like to calculate (⌊2^(1918)*π⌋+124476) in python but I get this error when I do it using the following code:

b = math.floor((2**1918) * math.pi) + 124476
print(b)

OverflowError: int too large to convert to float

How can you get this to work? In the end I just like to have it all as hexadecimal (if that helps with answering my question) but I was actually only trying to get it as an integer first :)

  • 1
    All the solutions I see to similar problems use the [decimal](https://docs.python.org/3/library/decimal.html) module, such as in [this question](https://stackoverflow.com/questions/16174399/overflowerror-long-int-too-large-to-convert-to-float-in-python) – G. Anderson Jun 12 '19 at 15:59
  • An int is just 8 bits I believe. Try to use 2.0**1918? – WiseDev Jun 12 '19 at 16:00
  • 5
    @BlueRineS An int is much more than 8 bits. – Thomas Jager Jun 12 '19 at 16:05

4 Answers4

2

The basic problem is what the message says. Python integers can be arbitrarily large, larger even than the range of a float. 2**1918 in decimal contains 578 significant digits and is way bigger than the biggest float your IEEE754 hardware can represent. So the call just fails.

You could try looking at the mpmath module. It is designed for floating point arithmetic outside the bounds of what ordinary hardware can handle.

BoarGules
  • 16,440
  • 2
  • 27
  • 44
2

The right solution really depends on how precise the results are required. Since 2^1918 already is too large for both standard integer and floating point containers, it is not possible to get away with direct calculations without loosing all the precision below ~ 10^300.

In order to compute the desired result, you should use arbitrary-precision calculation techniques. You can implement the algorithms yourself or use one of the available libraries.

Assuming you are looking for an integer part of your expression, it will take about 600 decimal places to store the results precisely. Here is how you can get it using mpmath:

from mpmath import mp
mp.dps = 600
print(mp.floor(mp.power(2, 1918)*mp.pi + 124476))

74590163000744215664571428206261183464882552592869067139382222056552715349763159120841569799756029042920968184704590129494078052978962320087944021101746026347535981717869532122259590055984951049094749636380324830154777203301864744802934173941573749720376124683717094961945258961821638084501989870923589746845121992752663157772293235786930128078740743810989039879507242078364008020576647135087519356182872146031915081433053440716531771499444683048837650335204793844725968402892045220358076481772902929784589843471786500160230209071224266538164123696273477863853813807997663357545.0

Next, all you have to do is to convert it to hex representation (or extract hex from its internal binary form), which is a matter for another subject :)

M0nZDeRR
  • 216
  • 3
  • 7
  • 1
    Note, that @MisterMiyagi 's answer is wrong, since the math.pi is a float constant and has a very low precision for your case. You can clearly see it by comparing the results (they begin to differ at 16th digit, which is the order of machine epsilon for double precision floats). – M0nZDeRR Jun 12 '19 at 16:32
  • 1
    That makes it imprecise, not wrong. The error is 3.8981718325193755e-17, which may or may not be acceptable. – MisterMiyagi Jun 12 '19 at 16:36
  • 2
    I get the error "No module named 'mpmath'. Do you know how I can fix that? :p –  Jun 12 '19 at 16:50
  • 1
    Ok - imprecise, so be it! However, the error is not the order of 10^-17, but is at least 10^**+15** (it depends how you evaluate the error). Since your result has only first 15 of 300 right, I assume is its rather wrong given that the question clearly suggests some precision at lower digits is desirable (otherwise + 124476 term is totally irrelevant). – M0nZDeRR Jun 12 '19 at 16:57
  • @tenepolis, did you try `pip install mpmath` before importing? – M0nZDeRR Jun 12 '19 at 17:00
  • No but I just did it and I still get the same error. I did use both 'pip install mpmath' and 'sudo apt-get install python-mpmath' –  Jun 12 '19 at 17:02
  • @m0nzderr Since the calculation shown evaluates to a *constant*, it is safe to assume not all relevant information of the use-case is presented. Otherwise, the most practical solution is not to bother with dependencies and precision and just to write out that constant. – MisterMiyagi Jun 12 '19 at 17:02
  • Never mind it's working now! Thank you everyone so much! :D –  Jun 12 '19 at 17:13
  • @tenepoiis Try to see if you get it installed via `pip list`. It may be something with your environment/architecture/pip version. I tried it now with both pip 9 / pyhton 2.7 and pip3 18 / 3.6 and ran worked smoothly. If nothing helps - you can also try to download it directly from http://mpmath.org/ (https://files.pythonhosted.org/packages/ca/63/3384ebb3b51af9610086b23ea976e6d27d6d97bf140a76a365bd77a3eb32/mpmath-1.1.0.tar.gz) and then install with `pip install mpmath-1.1.0.tar.gz`. – M0nZDeRR Jun 12 '19 at 17:16
  • 1
    I just realized the FLOOR was actually important in my question and has been left out in your answer. Maybe edit so it's saying 'print(mp.floor(mp.power(2, 1918)*mp.pi) + 124476)' –  Jun 12 '19 at 17:49
  • @tenepolis - right! Actualy mp.floor was already used to print the result, but somehow got lost in the answer. – M0nZDeRR Jun 13 '19 at 11:12
2

I think the problem can be solved without resorting to high-precision arithmetic. floor(n.something + m) where m and n are integers is equal to floor(n.something) + m. So in this case you are looking for floor(2**1918 * pi) plus an integer (namely 124476). floor(2**whatever * pi) is just the first whatever + 2 bits of pi. So just look up the first 1920 bits of pi, add the bits for 124476, and output as hex digits.

A spigot algorithm can generate digits of pi without using arbitrary precision. A quick web search seems to find some Python implementations for generating digits in base 10. I didn't see anything about base 2, but Plouffe's formula generates base 16 digits if I am not mistaken.

Robert Dodier
  • 16,905
  • 2
  • 31
  • 48
  • First 1920 bits of π, I guess, rather than the first 1918? (I'm fairly sure the context is [RFC 3526](https://www.ietf.org/rfc/rfc3526.txt), in which case these bits are being padded with 64 1-bits at each end to get a total of 1920 + 64 + 64 = 2048 bits.) – Mark Dickinson Jun 12 '19 at 18:50
  • Yes, you're right, I fixed the text. I figured that this was a made-up problem of some kind ... interesting to see the connection. – Robert Dodier Jun 12 '19 at 19:13
1

The problem is that (2**1918) * math.pi attempts to convert the integer to 64-bit floating point precision, which is insufficiently large. You can convert math.pi to a fraction to use arbitrary precision.

>>> math.floor((2**1918) * fractions.Fraction(math.pi) + 124476)
74590163000744212756918704280961225881025315246628098737524697383138220762542289800871336766911957454080350508173317171375032226685669280397906783245438534131599390699781017605377332298669863169044574050694427882869191541933796848577277592163846082732344724959222075452985644173036076895843129191378853006780204194590286508603564336292806628948212533561286572102730834409985441874735976583720122784469168008083076285020654725577288682595262788418426186598550864392013191287665258445673204426746083965447956681216069719524525240073122409298640817341016286940008045020172328756796

Note that arbitrary precision applies to the calculation; math.pi is defined only with 64-bit floating point precision. Use an external library, such as mpmath, if you need the exact value.

To convert this to a hexadecimal string, use hex or a string format:

>>> hex(math.floor((2**1918) * fractions.Fraction(math.pi) + 124476))
'0xc90fdaa22168c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e63c'
>>> '%x' % math.floor((2**1918) * fractions.Fraction(math.pi) + 124476)
'c90fdaa22168c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e63c'
>>> f'{math.floor((2**1918) * fractions.Fraction(math.pi) + 124476):X}'
'C90FDAA22168C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E63C'

For string formats, x provides lower-case hex whereas X provides upper-case case.

MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119