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.3
de 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
.0000000001
Ondalı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.FD
8 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 .
h
4 ile çarpın .
h×4 - h = h × (4-1) = h × 3 = 3×h
Sı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*h
onaltı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.FD
50 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.
dc
sadece 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.)