DC ile hassasiyet kaybı


12

dcOnaltılık noktaları ile bazı temel 16 sayıları işlemek için kullanmak istiyorum ama hassas sorunlar yaşıyorum. Örneğin, aşağıda ben çarparak ediyorum F423F.FDgöre 100, her iki onaltılık. Beklenen cevap F423FFD, bunun yerine F423FFA.E1, yuvarlamadan sonra bile yakın ama yeterince doğru değil.

$ dc
16 d i o F423F.FD 100 * p
F423FFA.E1

Bu dcsınırsız bir hassas hesap makinesi olduğunu okudum ve bu hiçbir şekilde çok fazla değil. Yanlış yaptığım bir şey var mı?

Cevaplarınız için teşekkürler. Sorunları göz önüne alındığında, dcmermiyi ısırdım ve diğer bazlardaki gerçek sayılar için kendi ayrıştırıcımı yazdım. Herkes kod ilgilenen varsa, ben burada gönderebilirsiniz.

Yanıtlar:


6

Sadece orijinal numarayı yazdırmanın yuvarlandığını gösterdiğine dikkat edin:

$ dc <<<'16 d i o F423F.FD p'
F423F.FA

Daha fazla hassasiyet için çok sayıda sıfır ekleyerek bunun üstesinden gelebilirsiniz:

$ dc <<<'16 d i o F423F.FD000000 100 * p'
F423FFD.0000000

Teşekkürler. Ben dcsadece doğrudan bir ayrıştırıcı yazmak için kullanmak için sayıları masaj daha fazla kod alarak düşünüyorum ! (Dolgu miktarı değişir, böylece giriş ya da bir ondalık sahip olabilir veya olmayabilir, ve diğer bazlar olabilir.)
Yimin Rong'u

2
Bunu kabul edilen cevap olarak işaretleyeceğim. dcYanıt vermekten sorumlu kişiler : Ondalık olmayan kesirli basamakları düzgün bir şekilde işlemek için dc ve bc tarafından kullanılan ondalık ölçekli modelden tamamen farklı bir model gerekir (bc için POSIX tarafından ve her ikisi için tarihsel geleneğe göre). , bu yüzden teknik olarak düzeltilebilir dc, ancak bu muhtemelen kırılacaktı bc, bu yüzden WONTFIX olarak sınıflandırıldı.
Yimin Rong

8

Ondalık ( dcdönüştürmek için kullanılarak) olarak ifade edilir , bu 999999.98 (aşağı yuvarlanır) × 256, yani 255999994.88'e karşılık gelir, bu da onaltılık olarak F423FFA.E1'dir.

Fark, dcyuvarlama davranışından gelir : 255999997 verecek 256 × (999999 + 253 ÷ 256) hesaplamak yerine, 253 ÷ 256 aşağı yuvarlar ve sonucu çarpar.

dcBir olan keyfi , istediğiniz herhangi hassasiyetle için hesaplayabilir araçlar hassas hesap makinesi, ama bunun ne olduğunu söylememiz gerekir. Varsayılan olarak, kesinlik değeri 0'dır, yani bölme yalnızca tamsayı değerleri üretir ve çarpma girişteki basamak sayısını kullanır. Hassasiyeti ayarlamak için kullanın k(ve giriş veya çıkış yarıçapından bağımsız olarak hassasiyetin her zaman ondalık basamak ile ifade edildiğini unutmayın):

10 k
16 d i o
F423FFD 100 / p
F423F.FD0000000
100 * p
F423FFD.000000000

(8 basamak hassasiyeti yeterli olacaktır, çünkü ondalık sayıyı 1 ÷ 256 olarak temsil etmeniz gerekir.)


1
Bu "keyfi hassasiyet" hesap makinesi için tamamen beklenmedik bir sonuç gibi görünüyor mu?
Yimin Rong

3
Ayarlandığında hala hassasiyeti kaybeder k: 10 k 16 d i o F423F.FD pF423F.FA, bu yüzden kullanmadan önce tüm sayıları ölçeklendirmeliyim dc. Temel olarak onları önceden ayrıştırmaya yöneliktir.
Yimin Rong

2
@Yimin evet, maalesef dcgirişini sadece bana bir hata gibi görünen basamak sayısını kullanarak ölçeklendiriyor (basamak sayısı giriş yarıçapı kullanılarak hesaplandığı, ancak ondalık değere uygulandığı için).
Stephen Kitt

1
Ne de bu @dhag POSIX belirtir (için bchangi dcdayanmaktadır): “İç hesaplamaları bakılmaksızın giriş ve çıkış üsleri, ondalık basamak sayıyı belirtilen gibi ondalık eğer yapılacaktır”
Stephen Kitt

1
Bu, bir sabitin nasıl ayrıştırıldığıyla ilgili bir sorundur. Deneyin 20 k 16 d i o 0.3 1 / p (.19999999999999999 yazdırır). Operasyon sadece bölen olduğunu anlamak 0.2tarafından 1(teoride değerini değiştirmez olmalıdır). İken 20 k 16 d i o 0.3000 1 / p(doğru) baskılar .30000000000000000. (Devamı)
Isaac

1

Sorun

Sorun dc (ve bc) 'nin sayısal sabitleri anlama biçimidir.
Örneğin, değer (onaltılı olarak) 0.3(1'e bölünür),0.2

$ dc <<<"20k 16 d i o 0.3 1 / p"
.199999999999999999999999999

Aslında, düz sabit 0.3de değişir:

$ dc <<<"20 k 16 d i o     0.3     p"
.1

Görünüşe göre garip bir şekilde, ama değil (daha sonra).
Daha fazla sıfır eklemek yanıt yaklaşımını doğru değer yapar:

$ dc <<<"20 k 16 d i o     0.30     p"
.2E

$ dc <<<"20 k 16 d i o     0.300     p"
.2FD

$ dc <<<"20 k 16 d i o     0.3000     p"
.3000

Son değer tamdır ve nasıl daha fazla sıfır eklenirse eklensin tam olarak kalacaktır.

$ dc <<<"20 k 16 d i o     0.30000000     p"
.3000000

Sorun bc'de de mevcuttur:

$ bc <<< "scale=20; obase=16; ibase=16;    0.3 / 1"
.19999999999999999

$ bc <<< "scale=20; obase=16; ibase=16;    0.30 / 1"
.2E147AE147AE147AE

$ bc <<< "scale=20; obase=16; ibase=16;    0.300 / 1"
.2FDF3B645A1CAC083

$ bc <<< "scale=20; obase=16; ibase=16;    0.3000 / 1"
.30000000000000000

Bit başına bir basamak mı?

Kayan nokta sayıları için sezgisel olmayan gerçek, gerekli basamak sayısının (noktadan sonra) ikili bit sayısına (noktadan sonra da) eşit olmasıdır. 0.101 ikili sayı, ondalık basamakta tam olarak 0.625'e eşittir. 0.0001110001 ikili sayısı (tam olarak) eşittir 0.1103515625(on ondalık basamak)

$ bc <<<'scale=30;obase=10;ibase=2; 0.101/1; 0.0001110001/1'; echo ".1234567890"
.625000000000000000000000000000
.110351562500000000000000000000
.1234567890

Ayrıca, ikili dosyada yalnızca bir (set) biti olan 2 ^ (- 10) gibi bir kayan nokta sayısı için:

$ bc <<<"scale=20; a=2^-10; obase=2;a; obase=10; a"
.0000000001000000000000000000000000000000000000000000000000000000000
.00097656250000000000

.0000000001Ondalık basamaklarla .0009765625(10) aynı sayıda ikili basamağa (10) sahiptir. Diğer bazlarda durum böyle olmayabilir, ancak taban 10, hem dc hem de bc'deki sayıların dahili temsilidir ve bu nedenle gerçekten dikkat etmemiz gereken tek tabandır.

Matematik kanıtı bu cevabın sonunda.

bc ölçeği

Noktadan sonraki basamak sayısı, scale()bc yerleşik işlev formu ile sayılabilir :

$ bc <<<'obase=16;ibase=16; a=0.FD; scale(a); a; a*100'
2
.FA
FA.E1

Gösterildiği gibi, 2 basamak sabiti temsil etmek için yetersizdir 0.FD.

Ayrıca, noktadan sonra kullanılan karakter sayısını saymak, sayının ölçeğini bildirmek (ve kullanmak) için çok yanlış bir yoldur. Bir sayının ölçeği (herhangi bir bazda), gerekli bit sayısını hesaplamalıdır.

Onaltılık bir kayan noktalı sayılar.

Bilindiği gibi her onaltılı basamak 4 bit kullanır. Bu nedenle, ondalık noktadan sonraki her onaltılık basamak, yukarıdaki (tek?) Gerçeğinden dolayı 4 ondalık basamak gerektiren 4 ikili basamak gerektirir.

Bu nedenle, benzeri bir sayı 0.FD8 ondalık basamağın doğru şekilde temsil edilmesini gerektirir:

$ bc <<<'obase=10;ibase=16;a=0.FD000000; scale(a);a;a*100'
8
.98828125
253.00000000

Sıfır ekle

Matematik basittir (onaltılık sayılar için):

  • Noktadan sonraki onaltılık basamak sayısını ( h) sayın .
  • h4 ile çarpın .
  • h×4 - h = h × (4-1) = h × 3 = 3×hSıfır ekleyin .

Kabuk kodunda (sh için):

a=F423F.FD
h=${a##*.}
h=${#h}
a=$a$(printf '%0*d' $((3*h)) 0)
echo "$a"

echo "obase=16;ibase=16;$a*100" | bc

echo "20 k 16 d i o $a 100 * p" | dc

Hangi yazdırılacaktır (hem dc hem de bc'de doğru şekilde):

$  sh ./script
F423F.FD000000
F423FFD.0000000
F423FFD.0000000

Dahili olarak, bc (veya dc), 3*honaltılık kayan noktalı sayıları dahili ondalık gösterime dönüştürmek için gerekli basamak sayısını yukarıda ( ) hesaplanan sayı ile eşleştirebilir . Veya diğer bazlar için başka bir işlev (basamak sayısının, bu diğer bazdaki baz 10'a (bc ve dc'nin iç kısmı) göre sonlu olduğu varsayılarak). 2 i (2,4,8,16, ...) ve 5,10 gibi.

pOSIX

Posix belirtimi şunları belirtir (dc'nin dayandığı bc için):

Dahili hesaplamalar, giriş ve çıkış tabanlarına bakılmaksızın, belirtilen sayıda ondalık basamağa kadar ondalık sanki yapılmalıdır.

Ancak "… belirtilen ondalık basamak sayısı." "ondalık iç hesaplamaları" etkilemeden (yukarıda açıklandığı gibi) sayısal sabiti temsil etmek için gereken ondalık basamak sayısı olarak anlaşılabilir.

Çünkü:

bc <<<'scale=50;obase=16;ibase=16; a=0.FD; a+1'
1.FA

bc, yukarıda ayarlandığı gibi gerçekten 50 ("belirtilen ondalık basamak sayısı") kullanmaz.

Yalnızca bölünmüşse dönüştürülür (sabit değeri 0.FD50 basamağa genişletmeden önce okumak için 2 ölçeğini kullandığından hala yanlıştır ):

$ bc <<<'scale=50;obase=16;ibase=16; a=0.FD/1; a'
.FAE147AE147AE147AE147AE147AE147AE147AE147A

Ancak, bu kesin:

$ bc <<<'scale=50;obase=16;ibase=16; a=0.FD000000/1; a'
.FD0000000000000000000000000000000000000000

Yine, sayısal dizeleri (sabitleri) okumak doğru sayıda bit kullanmalıdır.


Matematik kanıtı

İki adımda:

Bir ikili kesir a / 2 n olarak yazılabilir

İkili bir kesir, ikisinin negatif güçlerinin sonlu bir toplamıdır.

Örneğin:

= 0.00110101101 = 
= 0. 0     0      1     1      0      1     0      1      1     0       1

= 0 + 0 × 2 -1 + 0 × 2 -2 + 1 × 2 -3 + 1 × 2-4 + 0 × 2-5 + 1 × 2-6 + 0 × 2-7 + 1 × 2-8 + 1 × 2-9 + 0 × 2-10 + 1 × 2-11

= 2 -3 + 2-4 + 2-6 + 2-8 + 2-9 + 2-11 = (sıfırlar kaldırıldığında)

N bitlik ikili bir kesitteki son bit, 2 -n veya 1/2 n değerine sahiptir . Bu örnekte: 2-11 veya 1/2 11 .

= 1/2 3 + 1/2 4 + 1/2 6 + 1/2 8 + 1/2 9 + 1/2 11 = (ters)

Genel olarak, payda , iki pozitif pay üsüyle 2 n olabilir . Tüm terimler daha sonra tek bir değer a / 2 n olarak birleştirilebilir . Bu örnek için:

= 2 8 /2 11 + 2 7 /2 11 + 2 5 /2 11 + 2 3 /2 11 + 2 2 /2 11 + 1/2 11 = (2 ile ifade edilen 11 )

= (2 8 + 2 7 + 2 5 + 2 3 + 2 2 + 1) / 2 11 = (ortak faktör çıkarımı)

= (256 + 128 + 32 + 8 + 4 + 1) / 2 11 = (değere dönüştürüldü)

= 429/2 11

Her İkili Kesir b / 10 n olarak ifade edilebilir

A / 2 n'yi 5 n / 5 n ile çarpın (a × 5 n ) / (2 n × 5 n ) = (a × 5 n ) / 10 n = b / 10 n elde edin , burada b = a × 5 n . N basamağı vardır.

Örnek olarak:

(429 · 5 11 ) / 10 11 = 20947265625/10 11 = 0.20947265625

Her ikili kesirin aynı sayıda basamak içeren bir ondalık kesir olduğu gösterilmiştir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.