Set decimal on last two points - python

I dont find out how i can set the decimal (point) to the two last numbers...
I tried this '{0:.2f}'.format(a) but that makes like this '117085.00'
This is what i have
117085
55688
And i want
1170.85
556.88
So i need a point at the last two numbers.
And i dont want new numbers, i only need to set the point
Can someone help at this (easy i think) problem? :/ i am really new

In [33]: x = 117085
In [34]: x/100
Out[34]: 1170.85

The way that you are receiving your numbers, they are 100x the value you are trying to print. To format them the way you want, divide them by 100 before formatting them.
Additionally, the example you provide appears to be right-justified, meaning that the right side all lines up. If you want to accomplish that, you can use something like the below:
a = 117085
b = 55688
print('{0:>7.2f}'.format(a / 100))
print('{0:>7.2f}'.format(b / 100))
Output:
1170.85
556.88
Edit: Converted the rjust(7) to the format string >7
Let's break down the format string that we're using above...
{0:>7.2f} # The whole string
{ } # Brackets to denote a processed value
0 # Take the first argument passed through the `format()` function
: # A delimiter to separate the identifier (in this case, 0) from the format notation
>7 # Right justify this element, with a width of 7
.2f # Format the input as a float, with 2 digits to the right of the decimal point
Python implicitly assumes a few things apparently, so here's a shorter alternative:
{:7.2f} # The whole string
{ } # Brackets to denote a processed value
: # A delimiter to separate the identifier (in this case, assumed 0) from the format notation
7 # justify this element (Right justification by default), with a width of 7
.2f # Format the input as a float, with 2 digits to the right of the decimal point

Related

Fill up string of binary digits until certain length is reached

I have a string of ones and zeros, which typically has a length of 8*n, since they come from "n" bytes.
Now I want to arrange them into groups of five and I want to fill up the string with "0" until there are 16 5-bit "bytes" in total.
This is what I came up with but I can't figure out why this is not working.
while(len(binary_i) // (5*16) != 0):
binary_i = binary_i + "0"
Your problem seems to be that you're using // instead of %. Also, if you want to use a Python built-in alternative instead of using this while loop, try this:
binary_i.ljust(5*16, '0') # Fill `binary_i` using `0` up to 5*16 characters

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.

Python: Formatting int to 2 places

My function calculates numbers, which sometimes will be more than 100. If they are larger than 100 I want to remove the extra digits.
For example, lets say I have
percent=950
I want it to be reprinted as
percent=95
I do not want to convert to string, so I would rather not use slicing...
If you're willing to have a test to see if the number is > 100, you could do it like this:
>>> num = 95001
>>> int(str(num)[:2])
95
Though I'm unsure if you want to slice off the extra digits or store them as a decimal value. If you want to store them as a decimal value, go with mu's answer (making sure to cast at least one of the types to float if you're in Python 2 so you use float division).

How to right align and pad number with max width using format specification mini language

I need to be able to do this in a way that I can pass the format specification to the fmt parameter in numpy.savetxt(). I want to:
Take a float
Pad with zeros
Right align the number
Truncate to 8 digits with 3 decimal places (including negative signs)
I tried this:
'{:0>8}'.format('%.3f')
which I am passing to the numpy.savetxt() function but it is not able to truncate the values to the specified width of 8 digits.
for example:
import numpy as np
arr = np.random.random(10,10)*10
np.savetxt("testfile.txt", arr, fmt='{:0>8}'.format('%.3f')), delimiter='')
gives the output:
0000-11.54900006.870000021.8620000-0.3420000-20.55700005.5390000-2.343000012.1160000-8.949000012.097
00002.1510000-8.29800004.4310000-6.1050000-4.2280000-11.462000019.7120000-10.29800006.848000013.074
0000-0.536000010.8160000-10.329000011.328000017.5580000-2.83200007.795000012.10400001.834000011.550
0000-2.6060000-10.25000008.5310000-6.839000010.7350000-15.7570000-0.274000011.17500000.9940000-7.971
000022.6050000-1.4860000-2.37000000.806000010.3560000-8.86100002.430000018.6110000-3.1820000-5.281
000022.0720000-7.299000018.0320000-2.556000010.4690000-1.21900006.23900006.3840000-8.1560000-10.781
0000-2.0590000-4.8680000-22.31700005.0220000-9.5820000-2.873000021.6050000-0.9110000-9.7050000-4.920
0000-8.4410000-4.061000023.6880000-2.7050000-0.5700000-3.4070000-10.48900005.1820000-2.32500000.581
000016.9450000-19.11100002.955000018.28900000.62500003.34200003.1910000-14.7660000-4.93600002.139
000016.1390000-1.58100002.095000032.02800006.63900002.07300006.3080000-12.91900001.42500001.447
So obviously the values are not being truncated properly as each line should be the same length and each column should be fixed width essentially.
How can I modify that format specifier being passed to the fmt parameter of numpy's savetxt function to get the desired result?
The expression '{:0>8}'.format('%.3f') is evaluated immediately before savetxt ever gets a chance to even look at it. This means what savetxt sees from its perspective is simply the string '0000%.3f', which doesn't do what you want.
After looking at the various docs on the format specification, I think using fmt='%09.3f' should give you the results that you want. To dissect this:
The 0 means it's zero-padded.
The 9 means there are 9 characters (since . requires an extra character).
The .3 means there are 3 decimal places.
Lastly, the f specifies decimal notation (as opposed to scientific or other kinds of notation).
Floating-point numbers are padded to the right by default so there's no need to worry about that.

Float converted to 2.dp reverts to original number of decimal places when inserted into a string

I have created the following snippet of code and I am trying to convert my 5 dp DNumber to a 2 dp one and insert this into a string. However which ever method I try to use, always seems to revert the DNumber back to the original number of decimal places (5)
Code snippet below:
if key == (1, 1):
DNumber = '{r[csvnum]}'.format(r=row)
# returns 7.65321
DNumber = """%.2f""" % (float(DNumber))
# returns 7.65
Check2 = False
if DNumber:
if DNumber <= float(8):
Check2 = True
if Check2:
print DNumber
# returns 7.65
string = 'test {r[csvhello]} TESTHERE test'.format(r=row).replace("TESTHERE", str("""%.2f""" % (float(gtpe))))
# returns: test Hello 7.65321 test
string = 'test {r[csvhello]} TESTHERE test'.format(r=row).replace("TESTHERE", str(DNumber))
# returns: test Hello 7.65321 test
What I hoped it would return: test Hello 7.65 test
Any Ideas or suggestion on alternative methods to try?
It seems like you were hoping that converting the float to a 2-decimal-place string and then back to a float would give you a 2-decimal-place float.
The first problem is that your code doesn't actually do that anywhere. If you'd done that, you would get something very close to 7.65, not 7.65321.
But the bigger problem is that what you're trying to do doesn't make any sense. A float always has 53 binary digits, no matter what. If you round it to two decimal digits (no matter how you do it, including by converting to string and back), what you actually get is a float rounded to two decimal digits and then rounded to 53 binary digits. The closest float to 7.65 is not exactly 7.65, but 7.650000000000000355271368.* So, that's what you'd end up with. And there's no way around that; it's inherent to the way float is stored.
However, there is a different type you can use for this: decimal.Decimal. For example:
>>> f = 7.65321
>>> s = '%.2f' % f
>>> d = decimal.Decimal(s)
>>> f, s, d
(7.65321, '7.65', Decimal('7.65'))
Or, of course, you could just pass around a string instead of a float (as you're accidentally doing in your code already), or you could remember to use the .2f format every time you want to output it.
As a side note, since your DNumber ends up as a string, this line is not doing anything useful:
if DNumber <= 8:
In Python 2.x, comparing two values of different types gives you a consistent but arbitrary and meaningless answer. With CPython 2.x, it will always be False.** In a different Python 2.x implementation, it might be different. In Python 3.x, it raises a TypeError.
And changing it to this doesn't help in any way:
if DNumber <= float(8):
Now, instead of comparing a str to an int, you're comparing a str to a float. This is exactly as meaningless, and follows the exact same rules. (Also, float(8) means the same thing as 8.0, but less readable and potentially slower.)
For that matter, this:
if DNumber:
… is always going to be true. For a number, if foo checks whether it's non-zero. That's a bad idea for float values (you should check whether it's within some absolute or relative error range of 0). But again, you don't have a float value; you have a str. And for strings, if foo checks whether the string is non-empty. So, even if you started off with 0, your string "0.00" is going to be true.
* I'm assuming here that you're using CPython, on a platform that uses IEEE-754 double for its C double type, and that all those extra conversions back and forth between string and float aren't introducing any additional errors.
** The rule is, slightly simplified: If you compare two numbers, they're converted to a type that can hold them both; otherwise, if either value is None it's smaller; otherwise, if either value is a number, it's smaller; otherwise, whichever one's type has an alphabetically earlier name is smaller.
I think you're trying to do the following - combine the formatting with the getter:
>>> a = 123.456789
>>> row = {'csvnum': a}
>>> print 'test {r[csvnum]:.2f} hello'.format(r=row)
test 123.46 hello
If your number is a 7 followed by five digits, you might want to try:
print "%r" % float(str(x)[:4])
where x is the float in question.
Example:
>>>x = 1.11111
>>>print "%r" % float(str(x)[:4])
>>>1.11

Categories

Resources