Soruyu doğrudan yanıtlamak için, işte R işlevinden adlandırma kullanan sürümüm :
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)
Bu yanıtı göndermemdeki ana nedenim, "0.075" in 0.08 yerine 0.07'ye yuvarlandığından şikayet eden yorumlardır. Bunun nedeni, "Acemi C" tarafından belirtildiği gibi, hem sonlu kesinliğe hem de bir taban-2 gösterimine sahip kayan nokta aritmetiğinin bir kombinasyonudur . Gerçekte temsil edilebilecek 0,075'e en yakın sayı biraz daha küçüktür, bu nedenle yuvarlama, safça beklediğinizden farklı bir şekilde ortaya çıkar.
Ayrıca, bunun ondalık olmayan kayan nokta aritmetiğinin herhangi bir kullanımı için geçerli olduğuna dikkat edin, örneğin C ve Java'nın her ikisinde de aynı sorun vardır.
Daha ayrıntılı göstermek için Python'dan sayıyı "onaltılık" biçiminde biçimlendirmesini istiyoruz:
0.075.hex()
bize hangi veriyor: 0x1.3333333333333p-4
. Bunu yapmanın nedeni, normal ondalık gösterimin genellikle yuvarlamayı içermesi ve dolayısıyla bilgisayarın sayıyı gerçekte nasıl "gördüğü" değildir. Bu biçime alışkın değilseniz, birkaç yararlı referans Python belgeleri ve C standardıdır .
Bu sayıların nasıl çalıştığını biraz göstermek için, şunu yaparak başlangıç noktamıza geri dönebiliriz:
0x13333333333333 / 16**13 * 2**-4
hangi çıktı almalıdır 0.075
. 16**13
ondalık noktadan sonra 13 onaltılık hane 2**-4
olması ve onaltılık üslerin taban-2 olmasıdır.
Şimdi kayan değerlerin nasıl temsil edildiğine dair bir fikrimiz var, decimal
modülü bize biraz daha kesinlik vermek için kullanabiliriz ve bize neler olduğunu gösterebiliriz:
from decimal import Decimal
Decimal(0x13333333333333) / 16**13 / 2**4
vermek: 0.07499999999999999722444243844
ve umarım neden round(0.075, 2)
değerlendirildiğini açıklamak0.07