Fixed digits number in floats

本小妞迷上赌 提交于 2019-12-11 01:09:38

问题


I read a lot of discussion about this on SE, but still can't find the right one.

I want to plot some numbers, of various lengths, with the same number of digits.

For example I have: 12.345678, 1.2345678. Now, since I have to plot them with their error, I want that each one has a different format, in order that they are significant.

So, I want to plot them with a variable number of decimals. In my case, it makes no sense to plot 23.45678+/-1.23456 but better is 23.4+/-1.2. On the other hand, I need that 1.234567+/-0.034567 becomes 1.23+/-0.03.

So, let's say, I want to plot all the numbers with a fixed width, could be 3 digits in total plus the comma. I should use something like '%1.1f' %num, but I can't find the right way. How can I do that?


回答1:


I recommend defining a class that interprets a string formatter to give what you want.
Inside that class, you determine the length of the integer portion of your float and use that to define the appropriate string format.
In a nutshell, the class creates a formatter like '{:4.1f}' if your input is 12.345 (because you have two digits before the decimal separator) and {:4.2f} if your input it 1.2345 (because you have only one digit before the decimal separator). The total number of digits (4in this example) is provided as an input.
The new formatter is: {:nQ} where n is the total number of digits (so in the above example, you'd specify {:4Q}to get the output you want.
Here's the code:

import math

class IntegerBasedFloat(float):
    def __format__(self, spec):
        value = float(self)

        # apply the following only, if the specifier ends in Q
        # otherwise, you maintain the original float format
        if spec.endswith('Q'):
            # split the provided float into the decimal 
            # and integer portion (for this math is required):
            DEC, INT = math.modf(value)

            # determine the length of the integer portion:
            LEN = len(str(abs(int(INT))))

            # calculate the number of available decimals 
            # based on the overall length
            # the -1 is required because the separator 
            # requires one digit
            DECIMALS = int(spec[-2]) - LEN - 1

            if DECIMALS < 0:
                print 'Number too large for specified format'
            else:
                # create the corresponding float formatter
                # that can be evaluated as usual:
                spec = spec[-2] + '.' + str(DECIMALS) + 'f'

        return format(value, spec)

DATA = [12.345, 2.3456, 345.6789]

print '{:4Q}'.format(IntegerBasedFloat(DATA[0]))
print '{:4Q}'.format(IntegerBasedFloat(DATA[1]))
print '{:4Q}'.format(IntegerBasedFloat(DATA[2]))
print 'This is a "custom" float: {:5Q} and a "regular" float: {:5.3f}'.format(IntegerBasedFloat(12.3456),12.3456)

The output should be:

12.3
2.35
 346
This is a "custom" float: 12.35 and a "regular" float: 12.346

This answer is inspired by:
- splitting a number into the integer and decimal parts in python
- Add custom conversion types for string formatting



来源:https://stackoverflow.com/questions/25197194/fixed-digits-number-in-floats

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!