how python 3 handles big integers internally [duplicate] - python

In C, C++, and Java, an integer has a certain range. One thing I realized in Python is that I can calculate really large integers such as pow(2, 100). The same equivalent code, in C, pow(2, 100) would clearly cause an overflow since in 32-bit architecture, the unsigned integer type ranges from 0 to 2^32-1. How is it possible for Python to calculate these large numbers?

Basically, big numbers in Python are stored in arrays of 'digits'. That's quoted, right, because each 'digit' could actually be quite a big number on its own. )
You can check the details of implementation in longintrepr.h and longobject.c:
There are two different sets of parameters: one set for 30-bit digits,
stored in an unsigned 32-bit integer type, and one set for 15-bit
digits with each digit stored in an unsigned short. The value of
PYLONG_BITS_IN_DIGIT, defined either at configure time or in pyport.h,
is used to decide which digit size to use.
/* Long integer representation.
The absolute value of a number is equal to
SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i)
Negative numbers are represented with ob_size < 0;
zero is represented by ob_size == 0.
In a normalized number, ob_digit[abs(ob_size)-1] (the most significant
digit) is never zero. Also, in all cases, for all valid i,
0 <= ob_digit[i] <= MASK.
The allocation function takes care of allocating extra memory
so that ob_digit[0] ... ob_digit[abs(ob_size)-1] are actually available.
*/
struct _longobject {
PyObject_VAR_HEAD
digit ob_digit[1];
};

How is it possible for Python to calculate these large numbers?
How is it possible for you to calculate these large numbers if you only have the 10 digits 0-9? Well, you use more than one digit!
Bignum arithmetic works the same way, except the individual "digits" are not 0-9 but 0-4294967296 or 0-18446744073709551616.

Related

What happens when a float is cast to/from a boolean at the first principle level?

I'm trying to figure out what really happens under the hood when a float is cast to/from a bool in python. Here is the information I could find online and I was wondering if anyone else would be willing to step in and help me get an official understanding:
floats are represented in C as a 64-bit data structure and known as a double.
booleans are represented in C as 1's and 0's. If true -> 1 (binary form 0001) if false -> 0 (binary form 0000).
From this link here, I can see that there are really 3 parts to a double in memory. The sign, exponent, and fraction.
Working up from first principles I'm inclined to think that some combination of the exponent and fraction are used to be cast to float to boolean. For example 2^0 is 1 but e^x != 0 for all permutations of e and x respectively, so I'm really confused.
I have an interview tomorrow that is most likely going to ask me this question so I'm wondering if I could get some help figuring this out. Thanks and have a great day/night!
This seems to be the relevant code from https://github.com/python/cpython/blob/master/Objects/floatobject.c.
static int
float_bool(PyFloatObject *v)
{
return v->ob_fval != 0.0;
}
As we can see, the value v->ob_fval (a double) is compared to 0.0. If they compare unequal, the function returns a non-zero value, which Python then maps to the bool value True (or 1). If they compare equal, the function returns 0 (false), which Python maps to the bool value False (0).
So the question of how double is represented isn't really relevant at the level of the Python interpreter. The expression v->ob_fval != 0.0 will most likely map to a single hardware compare instruction. Most processors have dedicated hardware for floating point operations.
Comparing to 0 is slightly tricky, because IEEE floating point numbers have both a +0 and -0 representation (as you can see in the link you provided), so the hardware needs to check for the case where v->ob_fval is -0, but being compared to +0. But the hardware typically takes care of that, without Python (or even the C compiler) generally having to worry about that level of detail.
Your confusion about 2^0 and e^x isn't really relevant to the original question, but I think you are definitely confused, so I'd suggest reading your link again. The key is that the exponent in the double is not the exponent of the fractional part; it's the exponent of the constant value 2, and the fraction (plus 1) is multiplied by the result.
This has nothing to do with the internal representation of a float.
Booleans are a subclass of int, so float(True) == 1.0 and float(False) == 0.0.
Only 0.0 maps to False; all other floating-point values (including float("nan") and float("inf")) map to True.
In C
Converting a float to bool:
+0.0f, -0.0f --> false, all else float, including not-a-numbers, are true.
Internal float representation is irrelevant , only its value.
When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1 C11 §6.3.1.2 1
Converting a bool to float:
false --> 0.0f, true --> 1.0f
An object declared as type _Bool is large enough to store the values 0 and 1. §6.2.5 2

Round down/truncate large float [duplicate]

This is more of a numerical analysis rather than programming question, but I suppose some of you will be able to answer it.
In the sum two floats, is there any precision lost? Why?
In the sum of a float and a integer, is there any precision lost? Why?
Thanks.
In the sum two floats, is there any precision lost?
If both floats have differing magnitude and both are using the complete precision range (of about 7 decimal digits) then yes, you will see some loss in the last places.
Why?
This is because floats are stored in the form of (sign) (mantissa) × 2(exponent). If two values have differing exponents and you add them, then the smaller value will get reduced to less digits in the mantissa (because it has to adapt to the larger exponent):
PS> [float]([float]0.0000001 + [float]1)
1
In the sum of a float and a integer, is there any precision lost?
Yes, a normal 32-bit integer is capable of representing values exactly which do not fit exactly into a float. A float can still store approximately the same number, but no longer exactly. Of course, this only applies to numbers that are large enough, i. e. longer than 24 bits.
Why?
Because float has 24 bits of precision and (32-bit) integers have 32. float will still be able to retain the magnitude and most of the significant digits, but the last places may likely differ:
PS> [float]2100000050 + [float]100
2100000100
The precision depends on the magnitude of the original numbers. In floating point, the computer represents the number 312 internally as scientific notation:
3.12000000000 * 10 ^ 2
The decimal places in the left hand side (mantissa) are fixed. The exponent also has an upper and lower bound. This allows it to represent very large or very small numbers.
If you try to add two numbers which are the same in magnitude, the result should remain the same in precision, because the decimal point doesn't have to move:
312.0 + 643.0 <==>
3.12000000000 * 10 ^ 2 +
6.43000000000 * 10 ^ 2
-----------------------
9.55000000000 * 10 ^ 2
If you tried to add a very big and a very small number, you would lose precision because they must be squeezed into the above format. Consider 312 + 12300000000000000000000. First you have to scale the smaller number to line up with the bigger one, then add:
1.23000000000 * 10 ^ 15 +
0.00000000003 * 10 ^ 15
-----------------------
1.23000000003 <-- precision lost here!
Floating point can handle very large, or very small numbers. But it can't represent both at the same time.
As for ints and doubles being added, the int gets turned into a double immediately, then the above applies.
When adding two floating point numbers, there is generally some error. D. Goldberg's "What Every Computer Scientist Should Know About Floating-Point Arithmetic" describes the effect and the reasons in detail, and also how to calculate an upper bound on the error, and how to reason about the precision of more complex calculations.
When adding a float to an integer, the integer is first converted to a float by C++, so two floats are being added and error is introduced for the same reasons as above.
The precision available for a float is limited, so of course there is always the risk that any given operation drops precision.
The answer for both your questions is "yes".
If you try adding a very large float to a very small one, you will for instance have problems.
Or if you try to add an integer to a float, where the integer uses more bits than the float has available for its mantissa.
The short answer: a computer represents a float with a limited number of bits, which is often done with mantissa and exponent, so only a few bytes are used for the significant digits, and the others are used to represent the position of the decimal point.
If you were to try to add (say) 10^23 and 7, then it won't be able to accurately represent that result. A similar argument applies when adding a float and integer -- the integer will be promoted to a float.
In the sum two floats, is there any precision lost?
In the sum of a float and a integer, is there any precision lost? Why?
Not always. If the sum is representable with the precision you ask, and you won't get any precision loss.
Example: 0.5 + 0.75 => no precision loss
x * 0.5 => no precision loss (except if x is too much small)
In the general case, one add floats in slightly different ranges so there is a precision loss which actually depends on the rounding mode.
ie: if you're adding numbers with totally different ranges, expect precision problems.
Denormals are here to give extra-precision in extreme cases, at the expense of CPU.
Depending on how your compiler handle floating-point computation, results can vary.
With strict IEEE semantics, adding two 32 bits floats should not give better accuracy than 32 bits.
In practice it may requires more instruction to ensure that, so you shouldn't rely on accurate and repeatable results with floating-point.
In both cases yes:
assert( 1E+36f + 1.0f == 1E+36f );
assert( 1E+36f + 1 == 1E+36f );
The case float + int is the same as float + float, because a standard conversion is applied to the int. In the case of float + float, this is implementation dependent, because an implementation may choose to do the addition at double precision. There may be some loss when you store the result, of course.
In both cases, the answer is "yes". When adding an int to a float, the integer is converted to floating point representation before the addition takes place anyway.
To understand why, I suggest you read this gem: What Every Computer Scientist Should Know About Floating-Point Arithmetic.

Converting bitstring to 32-bit signed integer yields wrong result

I am trying to solve a challenge on this site. I have everything correct except I can't properly convert a bitstring to its 32-bit signed integer representation.
For example I have this bitstring:
block = '10101010001000101110101000101110'
My own way of converting this bitstring to 32-bit signed integer: I partially remember from school that first bit is the sign bit. If it is 1 we have negative number and vice versa.
when I do this, it gives me the number in base 10. It just converts it to base 10:
int(block, 2) #yields 2854414894
I have tried excluding the first bit and convert remaining 31 length bitstring, after that checked the first bit to decide whether this is negative number or not:
int(block[1:32], 2) #yields 706931246
But the correct answer is -1440552402. What operation should I do to this bitstring to get this integer? Is it relevant if the byte order of the system is little endian or big endian? My system is little endian.
In python there's no size for integers, so you'll never get a negative value with a high order 1 bit.
To "emulate" 32-bit behaviour just do this, since your 2854414894 value is > 2**31-1 aka 0x7FFFFFFF:
print(int(block[1:32], 2)-2**31)
you'll get
-1440552402
You're right that the upper bit determines sign, but it's not a simple flag. Instead, the whole character of negative numbers is inverted. This is a positive number 1 (in 8 bits):
00000001
This is a negative 1:
11111111
The upshot is that addition and subtraction "wrap around". So 4 - 1 would be:
0100 - 0001 = 0011
And so 0 - 1 is the same as 1_0000_0000 - 1. The "borrow" just goes off the top of the integer.
The general way to "negate" a number is "invert the bits, add 1". This works both ways, so you can go from positive to negative and back.
In your case, use the leading '1' to detect whether negation is needed, then convert to int, then maybe perform the negation steps. Note, however, that because python's int is not a fixed-width value, there's a separate internal flag (a Python int is not a "32-bit" number, it's an arbitrary-precision integer, with a dynamically allocated representation stored in some fashion other than simple 2's complement).
block = '10101010001000101110101000101110'
asnum = int(block, 2)
if block[0] == '1':
asnum ^= 0xFFFFFFFF
asnum += 1
asnum = -asnum
print(asnum)
You should check for when the input value is out of the positive range for 32 bit signed integers:
res = int(block, 2)
if res >= 2**31:
res -= 2**32
So first you interpret the number as an unsigned number, but when you notice the sign bit was set ( >= 2^31 ), you subtract 2^32 so to get the negative number.

Having problems with sqrt() in C

While writing a code for my class I managed to create a working example in Python that follows all of the requirements that my professor set out for us to achieve. But when I translate it into C to hand it in to my prof I found several problems that I thought that I managed to circumnavigate but it turns out that I was wrong.
One of the problems that I've found is when in Python I used the following code to determine if the square root is a natural number.
if (math.sqrt(a**2+b**2)%2)==1 or (math.sqrt(a**2+b**2)%2)==0:
When I translated this in C I found that I was getting error messages while trying to compile the code saying that I was trying to modulo floats with integers and a whole lot of other stuff.
I did a few test runs in C to get a feel of the environment around roots and found that a variable assigned as a float or double returns 0 if the root is a natural number.
#include<stdio.h>
#include<math.h>
int main()
{
float r_float_a, r_float_b;
int a=16,b=15,r_int_a,r_int_b;
r_float_a=sqrt(a);
r_float_b=sqrt(b);
r_int_a=sqrt(a);
r_int_b=sqrt(b);
printf("%d\n",r_float_a);
printf("%d\n",r_float_b);
printf("%d\n",r_int_a);
printf("%d\n",r_int_b);
}
But if I were to try to call out r_float_a in a if statement it would always return false no matter the value of a:
#include<stdio.h>
#include<math.h>
int main()
{
float r_float_a, r_float_b;
int a=16,b=15,r_int_a,r_int_b;
r_float_a=sqrt(a);
r_float_b=sqrt(b);
r_int_a=sqrt(a);
r_int_b=sqrt(b);
printf("%d\n",r_float_a);
printf("%d\n",r_float_b);
if (r_float_a==0)
{
printf("%d\n",r_int_a);
}
else
{
printf("%d\n",r_int_b);
}
}
How can I fix this to be able to check if the square root of a number is a natural number?
Obviously, if the number's square root is a natural (integer) number, so is the number itself.
unsigned a = 15;
unsigned root = (unsigned)sqrt(a);
if (root * root == a)
printf("%u has the natural square root %u\n", a, root);
else
printf("%u does not have a natural square root\n", a);
I used unsigned because a natural number is a whole, non-negative number. Therefore the use of signed numbers is outside the scope of this question. A square root can be negative but that would not be a natural number. The square root of a negative number enters the realm of complex numbers.
OP's and Weather Vane methods fail for large float. float typically has 6 to 8 decimal digits of precision. For numbers larger than 1e14, the sqrt(), saved as a float, will always be a whole number - convertible exactly to an integer (if in the integer range).
To determine if a float x is an exact square of another whole number:
Test if x is negative, INF or NaN and fail those pathological cases.
Use modff() to extract the fractional portion and if not 0.0, fail.
Use fmodf() to extract the mantissa/significand and exponent. Examine the exponent. Factor out even powers above the float bit width - reform x and then apply #Weather Vane test.

Maximum value for long integer

How can I assign the maximum value for a long integer to a variable, similar, for example, to C++'s LONG_MAX.
Long integers:
There is no explicitly defined limit. The amount of available address space forms a practical limit.
(Taken from this site). See the docs on Numeric Types where you'll see that Long integers have unlimited precision. In Python 2, Integers will automatically switch to longs when they grow beyond their limit:
>>> import sys
>>> type(sys.maxsize)
<type 'int'>
>>> type(sys.maxsize+1)
<type 'long'>
for integers we have
maxint and maxsize:
The maximum value of an int can be found in Python 2.x with sys.maxint. It was removed in Python 3, but sys.maxsize can often be used instead. From the changelog:
The sys.maxint constant was removed, since there is no longer a limit
to the value of integers. However, sys.maxsize can be used as an
integer larger than any practical list or string index. It conforms to
the implementation’s “natural” integer size and is typically the same
as sys.maxint in previous releases on the same platform (assuming the
same build options).
and, for anyone interested in the difference (Python 2.x):
sys.maxint The largest positive integer supported by Python’s regular
integer type. This is at least 2**31-1. The largest negative integer
is -maxint-1 — the asymmetry results from the use of 2’s complement
binary arithmetic.
sys.maxsize The largest positive integer supported by the platform’s
Py_ssize_t type, and thus the maximum size lists, strings, dicts, and
many other containers can have.
and for completeness, here's the Python 3 version:
sys.maxsize
An integer giving the maximum value a variable of type Py_ssize_t can take. It’s usually 2^31 - 1 on a 32-bit platform and
2^63 - 1 on a 64-bit platform.
floats:
There's float("inf") and float("-inf"). These can be compared to other numeric types:
>>> import sys
>>> float("inf") > sys.maxsize
True
Python long can be arbitrarily large. If you need a value that's greater than any other value, you can use float('inf'), since Python has no trouble comparing numeric values of different types. Similarly, for a value lesser than any other value, you can use float('-inf').
Direct answer to title question:
Integers are unlimited in size and have no maximum value in Python.
Answer which addresses stated underlying use case:
According to your comment of what you're trying to do, you are currently thinking something along the lines of
minval = MAXINT;
for (i = 1; i < num_elems; i++)
if a[i] < a[i-1]
minval = a[i];
That's not how to think in Python. A better translation to Python (but still not the best) would be
minval = a[0] # Just use the first value
for i in range(1, len(a)):
minval = min(a[i], a[i - 1])
Note that the above doesn't use MAXINT at all. That part of the solution applies to any programming language: You don't need to know the highest possible value just to find the smallest value in a collection.
But anyway, what you really do in Python is just
minval = min(a)
That is, you don't write a loop at all. The built-in min() function gets the minimum of the whole collection.
long type in Python 2.x uses arbitrary precision arithmetic and has no such thing as maximum possible value. It is limited by the available memory. Python 3.x has no special type for values that cannot be represented by the native machine integer — everything is int and conversion is handled behind the scenes.
Unlike C/C++ Long in Python have unlimited precision. Refer the section Numeric Types in python for more information.To determine the max value of integer you can just refer sys.maxint. You can get more details from the documentation of sys.
You can use: max value of float is
float('inf')
for negative
float('-inf')
A) For a cheap comparison / arithmetics dummy use math.inf. Or math.nan, which compares FALSE in any direction (including nan == nan) except identity check (is) and renders any arithmetics (like nan - nan) nan. Or a reasonably high real integer number according to your use case (e.g. sys.maxsize). For a bitmask dummy (e.g. in mybits & bitmask) use -1.
B) To get the platform primitive maximum signed long int (or long long):
>>> 256 ** sys.int_info.sizeof_digit // 2 - 1 # Python’s internal primitive
2147483647
>>> 256 ** ctypes.sizeof(ctypes.c_long) // 2 - 1 # CPython
2147483647
>>> 256 ** ctypes.sizeof(ctypes.c_longlong) // 2 - 1 # CPython
9223372036854775807
>>> 2**63 - 1 # Java / JPython primitive long
9223372036854775807
C) The maximum Python integer could be estimated by a long running loop teasing for a memory overflow (try 256**int(8e9) - can be stopped by KeyboardInterrupt). But it cannot not be used reasonably, because its representation already consumes all the memory and its much greater than sys.float_info.max.

Categories

Resources