UIに表示するには、フロートを丸める必要があります。たとえば、1つの有効数字に:
1234 -> 1000
0.12 -> 0.1
0.012 -> 0.01
0.062 -> 0.06
6253 -> 6000
1999 -> 2000
Pythonライブラリを使用してこれを行うための良い方法はありますか、それとも自分で作成する必要がありますか?
UIに表示するには、フロートを丸める必要があります。たとえば、1つの有効数字に:
1234 -> 1000
0.12 -> 0.1
0.012 -> 0.01
0.062 -> 0.06
6253 -> 6000
1999 -> 2000
Pythonライブラリを使用してこれを行うための良い方法はありますか、それとも自分で作成する必要がありますか?
負の数を使用して整数を丸めることができます。
>>> round(1234, -3)
1000.0
したがって、最上位桁のみが必要な場合:
>>> from math import log10, floor
>>> def round_to_1(x):
... return round(x, -int(floor(log10(abs(x)))))
...
>>> round_to_1(0.0232)
0.02
>>> round_to_1(1234243)
1000000.0
>>> round_to_1(13)
10.0
>>> round_to_1(4)
4.0
>>> round_to_1(19)
20.0
1より大きい場合は、floatを整数に変換する必要があります。
文字列フォーマットの%gは、いくつかの有効数字に丸められた浮動小数点をフォーマットします。'e'科学的記数法を使用することがあるため、丸められた文字列をfloatに変換してから、%s文字列の書式設定を行います。
>>> '%s' % float('%.1g' % 1234)
'1000'
>>> '%s' % float('%.1g' % 0.12)
'0.1'
>>> '%s' % float('%.1g' % 0.012)
'0.01'
>>> '%s' % float('%.1g' % 0.062)
'0.06'
>>> '%s' % float('%.1g' % 6253)
'6000.0'
>>> '%s' % float('%.1g' % 1999)
'2000.0'
有効な小数を1つ以外にしたい場合(それ以外の場合はEvgenyと同じ):
>>> from math import log10, floor
>>> def round_sig(x, sig=2):
... return round(x, sig-int(floor(log10(abs(x))))-1)
...
>>> round_sig(0.0232)
0.023
>>> round_sig(0.0232, 1)
0.02
>>> round_sig(1234243, 3)
1230000.0
f'{float(f"{i:.1g}"):g}'
# Or with Python <3.6,
'{:g}'.format(float('{:.1g}'.format(i)))
このソリューションは、次の理由で他のすべてのソリューションとは異なります。
任意の数n
の有効数字については、次を使用できます。
print('{:g}'.format(float('{:.{p}g}'.format(i, p=n))))
テスト:
a = [1234, 0.12, 0.012, 0.062, 6253, 1999, -3.14, 0., -48.01, 0.75]
b = ['{:g}'.format(float('{:.1g}'.format(i))) for i in a]
# b == ['1000', '0.1', '0.01', '0.06', '6000', '2000', '-3', '0', '-50', '0.8']
注:このソリューションでは、末尾のゼロの数が異なる数値を区別する標準的な方法がないため、入力から有効数字の数を動的に適応させることはできません(3.14 == 3.1400
)。そうする必要がある場合は、to-precisionパッケージで提供されているような非標準の関数が必要です。
私はあなたが望むことをする精度のパッケージを作成しました。それはあなたがあなたの数に多かれ少なかれ有効数字を与えることを可能にします。
また、指定された有効数字の数を使用して、標準、科学、および工学の表記法を出力します。
受け入れられた答えには、次の行があります
>>> round_to_1(1234243)
1000000.0
これは実際には8つの有効数字を指定します。番号1234243の場合、私のライブラリには有効数字が1つしか表示されません。
>>> from to_precision import to_precision
>>> to_precision(1234243, 1, 'std')
'1000000'
>>> to_precision(1234243, 1, 'sci')
'1e6'
>>> to_precision(1234243, 1, 'eng')
'1e6'
また、最後の有効数字を丸め、表記が指定されていない場合に使用する表記を自動的に選択できます。
>>> to_precision(599, 2)
'600'
>>> to_precision(1164, 2)
'1.2e3'
質問に直接答えるために、R関数からの命名を使用した私のバージョンは次のとおりです。
import math
def signif(x, digits=6):
if x == 0 or not math.isfinite(x):
return x
digits -= math.ceil(math.log10(abs(x)))
return round(x, digits)
この回答を投稿する主な理由は、「0.075」が0.08ではなく0.07に丸められるというコメントです。これは、「初心者C」で指摘されているように、有限の精度と2進数の表現の両方を持つ浮動小数点演算の組み合わせによるものです。実際に表現できる0.075に最も近い数値はわずかに小さいため、丸めは、単純に予想されるものとは異なる結果になります。
また、これは10進数以外の浮動小数点演算の使用にも当てはまります。たとえば、CとJavaの両方で同じ問題が発生します。
より詳細に表示するために、Pythonに数値を「16進数」形式でフォーマットするように依頼します。
0.075.hex()
これは私たちに:0x1.3333333333333p-4
。これを行う理由は、通常の10進数表現には丸めが含まれることが多く、したがって、コンピューターが実際に数値を「認識する」方法ではないためです。この形式に慣れていない場合は、PythonドキュメントとC標準を参照してください。
これらの数値がどのように機能するかを示すために、次のようにして開始点に戻ることができます。
0x13333333333333 / 16**13 * 2**-4
印刷する必要があります0.075
。 16**13
これは、小数点の後に13桁の16進数があり、2**-4
16進数の指数が基数2であるためです。
これで、フロートがどのように表現されるかがわかりました。モジュールを使用して、decimal
精度を高め、何が起こっているかを示すことができます。
from decimal import Decimal
Decimal(0x13333333333333) / 16**13 / 2**4
与える:0.07499999999999999722444243844
そしてうまくいけば、なぜround(0.075, 2)
評価するのかを説明する0.07
整数を有効数字1桁に丸める基本的な考え方は、ポイントの1桁前の浮動小数点に変換してから、元の整数サイズに戻すことです。
これを行うには、整数より10少ない10の最大の累乗を知る必要があります。これには、log10関数のフロアを使用できます。
from math import log10, floor def round_int(i,places): if i == 0: return 0 isign = i/abs(i) i = abs(i) if i < 1: return 0 max10exp = floor(log10(i)) if max10exp+1 < places: return i sig10pow = 10**(max10exp-places+1) floated = i*1.0/sig10pow defloated = round(floated)*sig10pow return int(defloated*isign)
def round_to_n(x, n):
if not x: return 0
power = -int(math.floor(math.log10(abs(x)))) + (n - 1)
factor = (10 ** power)
return round(x * factor) / factor
round_to_n(0.075, 1) # 0.08
round_to_n(0, 1) # 0
round_to_n(-1e15 - 1, 16) # 1000000000000001.0
うまくいけば、上記のすべての答えを最大限に活用します(1行のラムダとして配置できることを除いて;))。まだ調べていないので、この回答を自由に編集してください。
round_to_n(1e15 + 1, 11) # 999999999999999.9
負の数と小さい数(ゼロを含む)を処理するようにindgarのソリューションを変更しました。
from math import log10, floor
def round_sig(x, sig=6, small_value=1.0e-9):
return round(x, sig - int(floor(log10(max(abs(x), abs(small_value))))) - 1)
箱から出してこれを処理できるものは何も考えられません。ただし、浮動小数点数の場合はかなり適切に処理されます。
>>> round(1.2322, 2)
1.23
整数は扱いにくいです。それらは10進数としてメモリに保存されないため、重要な場所を実行するのは自然なことではありません。ただし、文字列になったら実装するのはかなり簡単です。
または整数の場合:
>>> def intround(n, sigfigs):
... n = str(n)
... return n[:sigfigs] + ('0' * (len(n)-(sigfigs)))
>>> intround(1234, 1)
'1000'
>>> intround(1234, 2)
任意の数値を処理する関数を作成したい場合、私の好みは、両方を文字列に変換し、小数点以下の桁数を探して何をするかを決定することです。
>>> def roundall1(n, sigfigs):
... n = str(n)
... try:
... sigfigs = n.index('.')
... except ValueError:
... pass
... return intround(n, sigfigs)
別のオプションは、タイプをチェックすることです。これは柔軟性がはるかに低く、Decimal
オブジェクトなどの他の数値とうまく連携しない可能性があります。
>>> def roundall2(n, sigfigs):
... if type(n) is int: return intround(n, sigfigs)
... else: return round(n, sigfigs)
文字列を使用せずに丸めたい場合は、上記のコメントに埋め込まれているリンクを見つけました。
http://code.activestate.com/lists/python-tutor/70739/
最高に私を襲う。次に、文字列フォーマット記述子を使用して印刷すると、適切な出力が得られ、数値表現を他の計算目的に使用できます。
リンクのコードは、def、doc、returnの3つのライナーです。バグがあります。対数の爆発をチェックする必要があります。それは簡単だ。入力をと比較しますsys.float_info.min
。完全なソリューションは次のとおりです。
import sys,math
def tidy(x, n):
"""Return 'x' rounded to 'n' significant digits."""
y=abs(x)
if y <= sys.float_info.min: return 0.0
return round( x, int( n-math.ceil(math.log10(y)) ) )
これは任意のスカラー数値に対して機能float
し、何らかの理由で応答をシフトする必要がある場合はnをaにすることができます。実際には、制限を次のようにプッシュできます。
sys.float_info.min*sys.float_info.epsilon
何らかの理由でごくわずかな値で作業している場合は、エラーを引き起こすことなく。
投稿された回答は、与えられたときに入手可能な最良のものでしたが、いくつかの制限があり、技術的に正しい有効数字を生成しません。
numpy.format_float_positionalは、目的の動作を直接サポートします。x
次のフラグメントは、科学的記数法が抑制された、有効数字4桁にフォーマットされたフロートを返します。
import numpy as np
x=12345.6
np.format_float_positional(x, precision=4, unique=False, fractional=False, trim='k')
> 12340.
Python 2.6以降の新しいスタイルのフォーマットの使用(%-styleは非推奨になっているため):
>>> "{0}".format(float("{0:.1g}".format(1216)))
'1000.0'
>>> "{0}".format(float("{0:.1g}".format(0.00356)))
'0.004'
Python 2.7以降では、先頭のを省略できます0
。
私もこれに遭遇しましたが、丸めタイプを制御する必要がありました。したがって、値、丸めタイプ、および必要な有効数字を考慮に入れることができるクイック関数(以下のコードを参照)を作成しました。
import decimal
from math import log10, floor
def myrounding(value , roundstyle='ROUND_HALF_UP',sig = 3):
roundstyles = [ 'ROUND_05UP','ROUND_DOWN','ROUND_HALF_DOWN','ROUND_HALF_UP','ROUND_CEILING','ROUND_FLOOR','ROUND_HALF_EVEN','ROUND_UP']
power = -1 * floor(log10(abs(value)))
value = '{0:f}'.format(value) #format value to string to prevent float conversion issues
divided = Decimal(value) * (Decimal('10.0')**power)
roundto = Decimal('10.0')**(-sig+1)
if roundstyle not in roundstyles:
print('roundstyle must be in list:', roundstyles) ## Could thrown an exception here if you want.
return_val = decimal.Decimal(divided).quantize(roundto,rounding=roundstyle)*(decimal.Decimal(10.0)**-power)
nozero = ('{0:f}'.format(return_val)).rstrip('0').rstrip('.') # strips out trailing 0 and .
return decimal.Decimal(nozero)
for x in list(map(float, '-1.234 1.2345 0.03 -90.25 90.34543 9123.3 111'.split())):
print (x, 'rounded UP: ',myrounding(x,'ROUND_UP',3))
print (x, 'rounded normal: ',myrounding(x,sig=3))
この関数は、数値が10 **(-decimal_positions)より大きい場合は通常のラウンドを実行します。それ以外の場合は、意味のある小数点以下の桁数に達するまで小数点以下を追加します。
def smart_round(x, decimal_positions):
dp = - int(math.log10(abs(x))) if x != 0.0 else int(0)
return round(float(x), decimal_positions + dp if dp > 0 else decimal_positions)
それが役に立てば幸い。
https://stackoverflow.com/users/1391441/gabriel、以下はrnd(.075、1)に関するあなたの懸念に対処していますか?警告:値を浮動小数点数として返します
def round_to_n(x, n):
fmt = '{:1.' + str(n) + 'e}' # gives 1.n figures
p = fmt.format(x).split('e') # get mantissa and exponent
# round "extra" figure off mantissa
p[0] = str(round(float(p[0]) * 10**(n-1)) / 10**(n-1))
return float(p[0] + 'e' + p[1]) # convert str to float
>>> round_to_n(750, 2)
750.0
>>> round_to_n(750, 1)
800.0
>>> round_to_n(.0750, 2)
0.075
>>> round_to_n(.0750, 1)
0.08
>>> math.pi
3.141592653589793
>>> round_to_n(math.pi, 7)
3.141593
これは文字列を返すため、小数部のない結果、およびE表記で表示される小さな値が正しく表示されます。
def sigfig(x, num_sigfig):
num_decplace = num_sigfig - int(math.floor(math.log10(abs(x)))) - 1
return '%.*f' % (num_decplace, round(x, num_decplace))
非常に徹底的に答えられた質問を与えられて、なぜ別のものを追加しませんか
上記の多くは同等ですが、これは私の美学に少しよく合います
import numpy as np
number=-456.789
significantFigures=4
roundingFactor=significantFigures - int(np.floor(np.log10(np.abs(number)))) - 1
rounded=np.round(number, roundingFactor)
string=rounded.astype(str)
print(string)
これは、個々の数値とnumpy配列に対して機能し、負の数に対しては正常に機能するはずです。
追加するステップが1つあります。np.round()は、丸めが整数であっても10進数を返します(つまり、significantFigures = 2の場合、-460が返されると予想されますが、代わりに-460.0が返されます)。これを修正するために、このステップを追加できます。
if roundingFactor<=0:
rounded=rounded.astype(int)
残念ながら、この最後のステップは数字の配列では機能しません。必要かどうかを判断するために、読者の皆様にお任せします。
import math
def sig_dig(x, n_sig_dig):
num_of_digits = len(str(x).replace(".", ""))
if n_sig_dig >= num_of_digits:
return x
n = math.floor(math.log10(x) + 1 - n_sig_dig)
result = round(10 ** -n * x) * 10 ** n
return float(str(result)[: n_sig_dig + 1])
>>> sig_dig(1234243, 3)
>>> sig_dig(243.3576, 5)
1230.0
243.36
これらの回答のほとんどは、数学、10進数、および/またはnumpyのインポートまたは文字列としての出力値を含みます。これは、大きい数と小さい数の両方を処理し、floatを出力するベースPythonの簡単なソリューションです。
def sig_fig_round(number, digits=3):
power = "{:e}".format(number).split('e')[1]
return round(number, -(int(power) - digits))
標準の10進ライブラリを使用した単純なバリアント
from decimal import Decimal
def to_significant_figures(v: float, n_figures: int) -> str:
d = Decimal(v)
d = d.quantize(Decimal((0, (), d.adjusted() - n_figures + 1)))
return str(d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize())
それをテストする
>>> to_significant_figures(1.234567, 3)
'1.23'
>>> to_significant_figures(1234567, 3)
'1230000'
>>> to_significant_figures(1.23, 7)
'1.23'
>>> to_significant_figures(123, 7)
'123'
この関数は正と負の両方の数値を取り、適切な有効数字の丸めを行います。
from math import floor
def significant_arithmetic_rounding(n, d):
'''
This function takes a floating point number and the no. of significant digit d, perform significant digits
arithmetic rounding and returns the floating point number after rounding
'''
if n == 0:
return 0
else:
# Checking whether the no. is negative or positive. If it is negative we will take the absolute value of it and proceed
neg_flag = 0
if n < 0:
neg_flag = 1
n = abs(n)
n1 = n
# Counting the no. of digits to the left of the decimal point in the no.
ld = 0
while(n1 >= 1):
n1 /= 10
ld += 1
n1 = n
# Counting the no. of zeros to the right of the decimal point and before the first significant digit in the no.
z = 0
if ld == 0:
while(n1 <= 0.1):
n1 *= 10
z += 1
n1 = n
# No. of digits to be considered after decimal for rounding
rd = (d - ld) + z
n1 *= 10**rd
# Increase by 0.5 and take the floor value for rounding
n1 = floor(n1+0.5)
# Placing the decimal point at proper position
n1 /= 10 ** rd
# If the original number is negative then make it negative
if neg_flag == 1:
n1 = 0 - n1
return n1
テスト:
>>> significant_arithmetic_rounding(1234, 3)
1230.0
>>> significant_arithmetic_rounding(123.4, 3)
123.0
>>> significant_arithmetic_rounding(0.0012345, 3)
0.00123
>>> significant_arithmetic_rounding(-0.12345, 3)
-0.123
>>> significant_arithmetic_rounding(-30.15345, 3)
-30.2
私は答えの1つを適応させました。私はこれが好き:
def sigfiground(number:float, ndigits=3)->float:
return float(f"{number:.{ndigits}g}")
それでもフロートが必要な場合に使用します(他の場所でフォーマットを行います)。