Strict Python formatting for floats - python

I'm using PYTHON to write to a file where the formatting is very strict. I have 10 available spaces in each column which cannot be exceeded.
I want to write the as many decimals as I can, but if the number is negative, the minus sign must be preferred over the last decimals. Also the period in the float must be counted into the number of available spaces. Numbers should be right trunctated
Example:
Let's say I want to print two numbers
a = 123.4567891011
b = 0.9876543210
Then I would want the result:
123.4567890.98765432
But if I now have the following:
a = -123.1111111111
b = 98765.432101234
c = 567
d = 0.1234
Then I'd want:
-123.1111198765.4321 567.0 0.1234
Would be to nice use exponential notation for high numbers, but not a necessity. I'm unable to find the answer. All I can find is to fix the format to number of significant digits, which really won't help me.
I've tried several methods of the
f.write({0:>10}{1:>10}.format(a,b))
but can't figure it out. Hope you see what I`m looking for.

Okay, so I found a way. I basically convert everything to strings and use:
f.write("{0:>10.10}{1:>10.10}".format(str(a),str(b)))
and so on..

Related

How to format numbers without rounding in Python?

I was searching online but could find if this is posible. I have a number, let say 1234.5963657 and I know that with f-string I can do this f"{number:,.2f}" to obtain 1,234.60.
The thing is that the number has been rounded, and I don't want that, I would like to obtain: 1,234.59. My question is if there's a way to do this as simple as the f-string.
If not, I would have to truncate it or do something like this:
number = 1234.5963657
int_part, dec_part = str(number).split('.')
new_number = f"{int_part}.{dec_part[:2]}" # 1234.59
Hope my question is clear. Thanks
Add one more digit of precision then use a slice to exclude the unwanted digit.
f"{number:,.3f}"[:-1]

Remove decimals from a Float column

shocked beyond belief how difficult this is turning out to be. All I can find are suggestions to change the format of the column to 'int' but I need to keep the comma thousand separators and changing the format to int gets rid of them. THEN i can't find anything on how to add comma separators to an int column. any ideas? really is nothing for me to share in addition to above in terms of what i've tried.
Format your floats...in a string format?
my_string = '{:,.0f}'. format(my_number)
E.g.:
x = 1000.00
'{:,.0f}'. format(x)-> 1,000
Which gives you what you want...something you can print with commas. 0f sets to 0 precision. (for how many decimal places)

Reconstructing two (string concatenated) numbers that were originally floats

Unfortunately the printing instruction of a code was written without an end-of-the-line character and one every 26 numbers consists of two numbers joined together. The following is a code that shows an example of such behaviour; at the end there is a fragment of the original database.
import numpy as np
for _ in range(2):
A=np.random.rand()+np.random.randint(0,100)
B=np.random.rand()+np.random.randint(0,100)
C=np.random.rand()+np.random.randint(0,100)
D=np.random.rand()+np.random.randint(0,100)
with open('file.txt','a') as f:
f.write(f'{A},{B},{C},{D}')
And thus the output example file looks very similar to what follows:
40.63358599010553,53.86722741700399,21.800795158561158,13.95828176311762557.217562728494684,2.626308403991772,4.840593988487278,32.401778122213486
With the issue being that there are two numbers 'printed together', in the example they were as follows:
13.95828176311762557.217562728494684
So you cannot know if they should be
13.958281763117625, 57.217562728494684
or
13.9582817631176255, 7.217562728494684
Please understand that in this case they are only two options, but the problem that I want to address considers 'unbounded numbers' which are type Python's "float" (where 'unbounded' means in a range we don't know e.g. in the range +- 1E4)
Can the original numbers be reconstructed based on "some" python internal behavior I'm missing?
Actual data with periodicity 27 (i.e. the 26th number consists of 2 joined together):
0.9221878978925224, 0.9331311610066017,0.8600582424784715,0.8754578588852764,0.8738648974725404, 0.8897837559800233,0.6773502027673041,0.736325377603136,0.7956454122424133, 0.8083168444596229,0.7089031184165164, 0.7475306242508357,0.9702361286847581, 0.9900689384633811,0.7453878225174624, 0.7749000030576826,0.7743879170108678, 0.8032590543649807,0.002434,0.003673,0.004194,0.327903,11.357262,13.782266,20.14374,31.828905,33.9260060.9215201173775437, 0.9349343132442707,0.8605282244327555,0.8741626682026793,0.8742163597524663, 0.8874673376386358,0.7109322043854609,0.7376362393985332,0.796158275345
To expand my comment into an actual answer:
We do have some information - An IEEE-754 standard float only has 32 bits of precision, some of which is taken up by the mantissa (not all numbers can be represented by a float). For datasets like yours, they're brushing up against the edge of that precision.
We can make that work for us - we just need to test whether the number can, in fact, be represented by a float, at each possible split point. We can abuse strings for this, by testing num_str == str(float(num_str)) (i.e. a string remains the same after being converted to a float and back to a string)
If your number is able to be represented exactly by the IEEE float standard, then the before and after will be equal
If the number cannot be represented exactly by the IEEE float standard, it will be coerced into the nearest number that the float can represent. Obviously, if we then convert this back to a string, will not be identical to the original.
Here's a snippet, for example, that you can play around with
def parse_number(s: str) -> List[float]:
if s.count('.') == 2:
first_decimal = s.index('.')
second_decimal = s[first_decimal + 1:].index('.') + first_decimal + 1
split_idx = second_decimal - 1
for i in range(second_decimal - 1, first_decimal + 1, -1):
a, b = s[:split_idx], s[split_idx:]
if str(float(a)) == a and str(float(b)) == b:
return [float(a), float(b)]
# default to returning as large an a as possible
return [float(s[:second_decimal - 1]), float(s[second_decimal - 1:])]
else:
return [float(s)]
parse_number('33.9260060.9215201173775437')
# [33.926006, 0.9215201173775437]
# this is the only possible combination that actually works for this particular input
Obviously this isn't foolproof, and for some numbers there may not be enough information to differentiate the first number from the second. Additionally, for this to work, the tool that generated your data needs to have worked with IEEE standards-compliant floats (which does appear to be the case in this example, but may not be if the results were generated using a class like Decimal (python) or BigDecimal (java) or something else).
Some inputs might also have multiple possibilities. In the above snippet I've biased it to take the longest possible [first number], but you could modify it to go in the opposite order and instead take the shortest possible [first number].
Yes, you have one available weapon: you're using the default precision to display the numbers. In the example you cite, there are 15 digits after the decimal point, making it easy to reconstruct the original numbers.
Let's take a simple case, where you have only 3 digits after the decimal point. It's trivial to separate
13.95857.217
The formatting requires a maximum of 2 digits before the decimal point, and three after.
Any case that has five digits between the points, is trivial to split.
13.958 57.217
However, you run into the "trailing zero" problem in some cases. If you see, instead
13.9557.217
This could be either
13.950 57.217
or
13.955 07.217
Your data do not contain enough information to differentiate the two cases.

How to dynamically format string representation of float number in python?

Hi I would like to dynamically adjust the displayed decimal places of a string representation of a floating point number, but i couldn't find any information on how to do it.
E.g:
precision = 8
n = 7.12345678911
str_n = '{0:.{precision}}'.format(n)
print(str_n) should display -> 7.12345678
But instead i'm getting a "KeyError". What am i missing?
You need to specify where precision in your format string comes from:
precision = 8
n = 7.12345678911
print('{0:.{precision}}'.format(n, precision=precision))
The first time, you specified which argument you'd like to be the number using an index ({0}), so the formatting function knows where to get the argument from, but when you specify a placeholder by some key, you have to explicitly specify that key.
It's a little unusual to mix these two systems, i'd recommend staying with one:
print('{number:.{precision}}'.format(number=n, precision=precision)) # most readable
print('{0:.{1}}'.format(n, precision))
print('{:.{}}'.format(n, precision)) # automatic indexing, least obvious
It is notable that these precision values will include the numbers before the point, so
>>> f"{123.45:.3}"
'1.23e+02'
will give drop drop the decimals and only give the first three digits of the number.
Instead, the f can be supplied to the type of the format (See the documentation) to get fixed-point formatting with precision decimal digits.
print('{number:.{precision}f}'.format(number=n, precision=precision)) # most readable
print('{0:.{1}f}'.format(n, precision))
print('{:.{}f}'.format(n, precision)) # automatic indexing, least obvious
In addition to #Talon, for those interested in f-strings, this also works.
precision = 8
n = 7.12345678911
print(f'{n:.{precision}f}')

How to divide large numbers with a floating point?

I have some large numbers (like 10000000 digits in total or more). Since I will lose precision, they are stored like strings.
Lets take some 'small' numbers as an example (some numbers also can be integers):
a = 4782916578987656789087654678908765467417657489104.9486718490129876578
b = 657890876566567890.8765467890987654
I want to make some operations on them.
Division. Well, answer is 7.270075858095143e+30
Multiplicaiton: 3.1466371806949598e+66
And so on.
Desirable output is full number as string, but with given precision for floating point with trancated zeros and rest.
Example:
888888888888.23 / 2.5122217 == 353825814373.082590504959329565857965
(24 digits after 'point')`
I've tried decimals module, but it can't handle big integers: class 'decimal.DivisionImpossible and maybe something else what I'm not aware of.
Is there is a way to do it with standard library, or at least numpy. Or maybe some algorithm what I can also reproduce in some other languages like JavaScript?
Note: I know I can make Decimal.getcontext().prec = 8888888888888 or bigger, but it will took more time to calculate, and what if numbers are 1 and 1.7373 do I need to waste resources on it? Also it's precision for whole number, not only 'floating' digits.
The decimal module is your friend here. If you want to go wild, well...
import decimal
from decimal import Decimal
import sys
c = decimal.getcontext()
c.prec = 899_999_768
c.Emax = decimal.MAX_EMAX
c.Emin = decimal.MIN_EMIN
a = Decimal('149846549e500000')
b = Decimal('254984984e449')
d = a / b
f = a * b
Remember that c.prec gives you the number of digits that are shown when you print it. According to the documentation, the maximum number is 999999999999999999, and you are bound to the memory of your computer. In my case (my computer, actually), c.prec is a good number before the computer breaks.
If you print the results, what happens?
print(f'{d}')
print(f'{f}')
Since you want to play with big, big numbers, well, there you have it.
P.S. I am trying to write a number with 10 000 000 digits, but my text editors don't allow that... they freeze.

Categories

Resources