How to convert strings to numbers in python while preserving fractional parts - python

Here is example
In > int('1.5')
Out > 1
In > int('10.5')
Out > 10
But I want to keep values intact. How do you do it?

Integers are only numbers that have no decimals.
-4,-3,-2,-1,0,1,2,3,4,...,65535 etc...
Floating point numbers or Decimal numbers are allowed to represent fractions and more precise numbers
10.5, 4.9999999
If you want to take a string and get a numerical type for non-whole numbers, use float()
float('10.5')
Here is a very simple elementary school explanation of integers
Here is the python documentation of numerical types

foo = 10.5
foo2 = int(foo)
print foo, foo2
10.5, 10

Integer can one represent whole number.
If you have a known consistent number of digest after the the comma, I recommend multiplying the number by 10 to the power of X.
Or round the number to the nearest whole number

Related

Taking just two decimals without rounding it

Basically, I have a list of float numbers with too many decimals. So when I created a second list with two decimals, Python rounded them. I used the following:
g1= ["%.2f" % i for i in g]
Where g1 is the new list with two decimals, but rounded, and g is the list with float numbers.
How can I make one without rounding them?
I'm a newbie, btw. Thanks!
So, you want to truncate the numbers at the second digit?
Beware that rounding might be the better and more accurate solution anyway.
If you want to truncate the numbers, there are a couple of ways - one of them is to multiply the number by 10 elevated to the number of desired decimal places (100 for 2 places), apply "math.floor", and divide the total back by the same number.
However, as internal floating point arithmetic is not base 10, you'd risk getting more decimal places on the division to scale down.
Another way is to create a string with 3 digits after the "." and drop the last one - that'd be rounding proof.
And again, keep in mind that this converts the numbers to strings - what should be done for presentation purposes only. Also, "%" formatting is quite an old way to format parameters in a string. In modern Python, f-strings are the preferred way:
g1 = [f"{number:.03f}"[:-1] for number in g]
Another, more correct way, is, of course, treat numbers as numbers, and not play tricks on adding or removing digits on it. As noted in the comments, the method above would work for numbers like "1.227", that would be kept as "1.22", but not for "2.99999", which would be rounded to "3.000" and then truncated to "3.00".
Python has the decimal modules, which allows for arbitrary precision of decimal numbers - which includes less precision, if needed, and control of the way Python does the rounding - including rounding towards zero, instead of the nearest number.
Just set the decimal context to the decimal.ROUND_DOWN strategy, and then convert your numbers using either the round built-in (the exact number of digits is guaranteed, unlike using round with floating point numbers), or just do the rounding as part of the string formatting anyway. You can also convert your floats do Decimals in the same step:
from decimals import Decimal as D, getcontext, ROUND_DOWN
getcontext().rounding = ROUND_DOWN
g1 = [f"{D(number):.02f}" for number in g]
Again - by doing this, you could as well keep your numbers as Decimal objects, and still be able to perform math operations on them:
g2 = [round(D(number, 2)) for number in g]
Here is my solution where we don't even need to convert the number's to string to get the desired output:
def format_till_2_decimal(num):
return int(num*100)/100.0
g = [-5.427926, -12.222018, 7.214379, -16.771845, -6.1441464, 10.1383295, 14.740516, 5.9209185, -9.740783, -10.098338]
formatted_g = [format_till_2_decimal(num) for num in g]
print(formatted_g)
Hope this solution helps!!
Here might be the answer you are looking for:
g = [-5.427926, -12.222018, 7.214379, -16.771845, -6.1441464, 10.1383295, 14.740516, 5.9209185, -9.740783, -10.098338]
def trunc(number, ndigits=2):
parts = str(number).split('.') # divides number into 2 parts. for ex: -5, and 4427926
truncated_number = '.'.join([parts[0], parts[1][:ndigits]]) # We keep this first part, while taking only 2 digits from the second part. Then we concat it together to get '-5.44'
return round(float(truncated_number), 2) # This should return a float number, but to make sure it is roundded to 2 decimals.
g1 = [trunc(i) for i in g]
print(g1)
[-5.42, -12.22, 7.21, -16.77, -6.14, 10.13, 14.74, 5.92, -9.74, -10.09]
Hope this helps.
Actually if David's answer is what you are looking for, it can be done simply as following:
g = [-5.427926, -12.222018, 7.214379, -16.771845, -6.1441464, 10.1383295, 14.740516, 5.9209185, -9.740783, -10.098338]
g1 = [("%.3f" % i)[:-1] for i in g]
Just take 3 decimals, and remove the last chars from the result strings. (You may convert the result to float if you like)

Print floating point number with a set number of significant digits (non-scientific)

I want to print floating point numbers with a set number of significant (i.e. non-zero) digits, but avoid the scientific notation (e).
So, for example, the number 0.000000002343245345 should be printed as 0.000000002343 (and not 2.343e-09)
I know how to define number of significant digits with an e notation:
>>>print('{:.3e}'.format(0.000000002343245345))
2.343e-09
And how to print a set number of decimal places without e-notation:
>>>print('{:.12f}'.format(0.000000002343245345))
0.000000002343
but not how to combine the two.
is there any simple way of doing so?
Here is some code that usually does what you want.
x = 0.000000002343245345
n = 4
from math import log10, floor
print('{:.{}f}'.format(x, n - floor(log10(x)) - 1))
Note that, due to the lack of exactness in floating-point arithmetic, that this may occasionally give a wrong answer. For example, the floor(log10()) may be one off from what is expected at or very near negative powers of 10 such as 0.1, 0.01, 0.001, and so on. My code seems to work well with those values but that is not guaranteed.
Also, there is no reasonable answer for some combinations of x and n. For example, what do you expect to result from x = 200000 and n = 4? There is no good answer, and my code gives the error
ValueError: Format specifier missing precision
You have to calculate the number of digits yourself. For four significant digits, this would be
number = 0.000000002343245345
digits = 4 - int(math.ceil(math.log10(number)))
print("{:.{}f}".format(number, digits))
# 0.000000002343

How to generate random number with a large number of decimals in Python?

How it's going?
I need to generate a random number with a large number of decimal to use in advanced calculation.
I've tried to use this code:
round(random.uniform(min_time, max_time), 1)
But it doesn't work for length of decimals above 15.
If I use, for e.g:
round(random.uniform(0, 0.5), 100)
It returns 0.586422176354875, but I need a code that returns a number with 100 decimals.
Can you help me?
Thanks!
100 decimals
The first problem is how to create a number with 1000 decimals at all.
This won't do:
>>> 1.23456789012345678901234567890
1.2345678901234567
Those are floating point numbers which have limitations far from 100 decimals.
Luckily, in Python, there is the decimal built-in module which can help:
>>> from decimal import Decimal
>>> Decimal('1.2345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901')
Decimal('1.2345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901')
Decimal can have any precision you need and it won't introduce floating point errors, but it will be much slower.
random
Now you just have to create a string with 100 decmals and give it to Decimal.
This will create one random digit:
random.choice('0123456789')
This will create 100 random digits and concatenate them:
''.join(random.choice('0123456789') for i in range(100))
Now just create a Decimal:
Decimal('0.' + ''.join(random.choice('0123456789') for i in range(100)))
This creates a number between 0 and 1. Multiply it or divide to get a different range.

append integer with comma in python

I have a function that assigns a number to a variable, and then append this number as an integer in a list. The numbers assigned may or may not have a comma.
for number in values:
list_of_values.append(int(number))
#do a few calculations for some of the numbers in the list
But this will just create a list where each number is rounded to a integer. How can I append the number as an integer and still retain its "true" value, without it being rounded?
edit:
sample values:
"0", "2", "1.5", "0.5", ...
If you wanted to represent real numbers (numbers with decimals behind a decimal point, or, in some locales, after the comma), then you should not use int() to represent these.
Use float() or decimal.Decimal() to represent the numbers instead:
list_of_values.append(float(number))
int() represents the number as an integer number, which by definition do not have a decimal component. If you don't want rounded numbers, don't use integers.
Whether you pick float() or decimal.Decimal() depends on your precision and performance needs. float() arithmetic can be handled in CPU hardware but are less precise (decimals are approximated using binary fractions), decimal.Decimal() preserves precision but arithmetic is slower.
the integer datatype is not able to hold floating values!
therefore you could use the float datatype instead!
list_of_values.append(float(number))

Safest way to convert float to integer in python?

Python's math module contain handy functions like floor & ceil. These functions take a floating point number and return the nearest integer below or above it. However these functions return the answer as a floating point number. For example:
import math
f=math.floor(2.3)
Now f returns:
2.0
What is the safest way to get an integer out of this float, without running the risk of rounding errors (for example if the float is the equivalent of 1.99999) or perhaps I should use another function altogether?
All integers that can be represented by floating point numbers have an exact representation. So you can safely use int on the result. Inexact representations occur only if you are trying to represent a rational number with a denominator that is not a power of two.
That this works is not trivial at all! It's a property of the IEEE floating point representation that int∘floor = ⌊⋅⌋ if the magnitude of the numbers in question is small enough, but different representations are possible where int(floor(2.3)) might be 1.
To quote from Wikipedia,
Any integer with absolute value less than or equal to 224 can be exactly represented in the single precision format, and any integer with absolute value less than or equal to 253 can be exactly represented in the double precision format.
Use int(your non integer number) will nail it.
print int(2.3) # "2"
print int(math.sqrt(5)) # "2"
You could use the round function. If you use no second parameter (# of significant digits) then I think you will get the behavior you want.
IDLE output.
>>> round(2.99999999999)
3
>>> round(2.6)
3
>>> round(2.5)
3
>>> round(2.4)
2
Combining two of the previous results, we have:
int(round(some_float))
This converts a float to an integer fairly dependably.
That this works is not trivial at all! It's a property of the IEEE floating point representation that int∘floor = ⌊⋅⌋ if the magnitude of the numbers in question is small enough, but different representations are possible where int(floor(2.3)) might be 1.
This post explains why it works in that range.
In a double, you can represent 32bit integers without any problems. There cannot be any rounding issues. More precisely, doubles can represent all integers between and including 253 and -253.
Short explanation: A double can store up to 53 binary digits. When you require more, the number is padded with zeroes on the right.
It follows that 53 ones is the largest number that can be stored without padding. Naturally, all (integer) numbers requiring less digits can be stored accurately.
Adding one to 111(omitted)111 (53 ones) yields 100...000, (53 zeroes). As we know, we can store 53 digits, that makes the rightmost zero padding.
This is where 253 comes from.
More detail: We need to consider how IEEE-754 floating point works.
1 bit 11 / 8 52 / 23 # bits double/single precision
[ sign | exponent | mantissa ]
The number is then calculated as follows (excluding special cases that are irrelevant here):
-1sign × 1.mantissa ×2exponent - bias
where bias = 2exponent - 1 - 1, i.e. 1023 and 127 for double/single precision respectively.
Knowing that multiplying by 2X simply shifts all bits X places to the left, it's easy to see that any integer must have all bits in the mantissa that end up right of the decimal point to zero.
Any integer except zero has the following form in binary:
1x...x where the x-es represent the bits to the right of the MSB (most significant bit).
Because we excluded zero, there will always be a MSB that is one—which is why it's not stored. To store the integer, we must bring it into the aforementioned form: -1sign × 1.mantissa ×2exponent - bias.
That's saying the same as shifting the bits over the decimal point until there's only the MSB towards the left of the MSB. All the bits right of the decimal point are then stored in the mantissa.
From this, we can see that we can store at most 52 binary digits apart from the MSB.
It follows that the highest number where all bits are explicitly stored is
111(omitted)111. that's 53 ones (52 + implicit 1) in the case of doubles.
For this, we need to set the exponent, such that the decimal point will be shifted 52 places. If we were to increase the exponent by one, we cannot know the digit right to the left after the decimal point.
111(omitted)111x.
By convention, it's 0. Setting the entire mantissa to zero, we receive the following number:
100(omitted)00x. = 100(omitted)000.
That's a 1 followed by 53 zeroes, 52 stored and 1 added due to the exponent.
It represents 253, which marks the boundary (both negative and positive) between which we can accurately represent all integers. If we wanted to add one to 253, we would have to set the implicit zero (denoted by the x) to one, but that's impossible.
If you need to convert a string float to an int you can use this method.
Example: '38.0' to 38
In order to convert this to an int you can cast it as a float then an int. This will also work for float strings or integer strings.
>>> int(float('38.0'))
38
>>> int(float('38'))
38
Note: This will strip any numbers after the decimal.
>>> int(float('38.2'))
38
math.floor will always return an integer number and thus int(math.floor(some_float)) will never introduce rounding errors.
The rounding error might already be introduced in math.floor(some_large_float), though, or even when storing a large number in a float in the first place. (Large numbers may lose precision when stored in floats.)
Another code sample to convert a real/float to an integer using variables.
"vel" is a real/float number and converted to the next highest INTEGER, "newvel".
import arcpy.math, os, sys, arcpy.da
.
.
with arcpy.da.SearchCursor(densifybkp,[floseg,vel,Length]) as cursor:
for row in cursor:
curvel = float(row[1])
newvel = int(math.ceil(curvel))
Since you're asking for the 'safest' way, I'll provide another answer other than the top answer.
An easy way to make sure you don't lose any precision is to check if the values would be equal after you convert them.
if int(some_value) == some_value:
some_value = int(some_value)
If the float is 1.0 for example, 1.0 is equal to 1. So the conversion to int will execute. And if the float is 1.1, int(1.1) equates to 1, and 1.1 != 1. So the value will remain a float and you won't lose any precision.

Categories