2013-04-02 6 views
7

En yakın tam sayıya bölünme sonucunun yuvarlanması pretty simple. Ama bölümlemenin bir sonucunu tamamlamaya çalışıyorum, böylece sonraki operasyon en iyi yaklaşımı verecektir. Bu en iyi, basit bir işlev tarafından anlatılmış:Yuvarlama y = x * x en yakın

const int halfbits = std::numeric_limits<unsigned int>::digits/2; 
unsigned x = foo(); // Likely big. 
unsigned x_div = x >> halfbits; // Rounded down 
unsigned y = x_div * x_div; // Will fit due to division. 

Ben 1<<(halfbits-1) ekleyerek en yakın x_div tamamlayabilirler. Fakat x² doğrusal bir fonksiyon olmadığı için, y genelde doğru şekilde yuvarlanmamıştır. Daha büyük tipleri kullanmadan (x*x) >> (halfbits*2) hesaplamak için basit ve daha doğru bir yolu var mı?

x_div'e 3<<(halfbits-3) eklenmesi yuvarlamayı iyileştirir, ancak bunun en iyi çözüm olduğunu kanıtlayamaz. Ayrıca, bu xⁿ için genelleştirilmiş olabilir?

numaralı telefonu düzenle: popüler taleple soruyu, saf aritmetik terimlerle "çevirme" özgürlüğünü (bu C bit kaydırıcı şeyden hiçbiri ...) almam.
Not: Tüm bölümler daha sonra tamsayı bölümleridir, örneğin 13/3 4 olur.
Sorun: x^2 hesaplayamayız çünkü x büyüktür, dolayısıyla bunun yerine hesaplama yapmak isteriz (x^2)/(2^H).
bu yüzden hesaplamak
x_div = X/sqrt (2^K)
yapmak için Ardından da kare:
y = x_div * x_div

Bununla birlikte, bu sonuç, (x^2)/(2^N) tam değeri, tipik olarak kısa ve OP daha iyi sonuçlara ulaşmak için 0.5 * sqrt (2^N) veya belki 0.375 * sqrt (2^N) eklemeyi önerir ...

Oli Charlesworth 'un yanıtı, gerçek değer, x^2 (x_hi + x_lo)^2 olarak düşünerek.

+7

Bit ops'ları ile kaybolmadım, ama belki de işlemleri matematiksel merkezli ve daha az merkezli bir şekilde yeniden ifade edebilir misiniz? Akıl almaz olmaya çalışmıyorum, sadece sorunun çözülmesine yardımcı olacağını ve hedefinizi belirlemeye yardımcı olacağını düşünüyorum. –

+0

Denenmesi gereken birkaç şey: 'x_div_down * x_div_up',' x_div_near * x_div_near'. Eğer zamanı harcamaya istekliyseniz, '' (x_div * x_rest) >> (halfbit-1) ''i hesaplayabilir ve sonucu düzeltebilirsiniz. –

+0

Yani, sadece (x * x) >> (halfbits * 2) 'tarafından ima edilen, açık olmak gerekirse, aslında * yuvarlanmamış * bit-doğru sonucu? Yoksa matematiksel sonucun doğru bir şekilde yuvarlanmasını ister misiniz? – hyde

cevap

8

x_div kesilmesi ile en fazla 1 büyüklükte bir hata büyüklüğü neden olacak, x_div*x_div ile hata en çok 1<<(half_digits+2) olabilir.

x * x = (x_lo + x_hi) * (x_lo + x_hi) 
     = x_lo^2 + x_hi^2 + 2*x_lo*x_hi 

nerede x_lo ve x_hi sırasıyla x alt ve üst yarıları şunlardır:

(long multplication kullanarak) aşağıdaki gibi bu squaring ifade edebiliriz düşünün, neden görmek için. Gördüğümüz gibi

MSB  :  :  :  LSB 
    +------+------+  :  : 
    | x_hi^2 |  :  : 
    +-----++-----++-----+:  : 
    :  | 2*x_lo*x_hi |:  : 
    :  +------++-----++------+ 
    :  :  | x_lo^2 | 
    :  :  +------+------+ 
    :<----------->:  :  : 
    Our result 

, alt dereceden terimleri nihai sonucu birden bitlerini etkiler: Bazı güzel ASCII sanatı ile, bu tüm satır yukarı nasıl düşünebilirsiniz. Bununla birlikte, bu terimlerin her birinin taşma olmadan orijinal türüne sığması gerekir. Böylece uygun vites değiştirme ve maskeleme ile istenilen sonucu alabiliriz.

Elbette, daha büyük bir yazı tipi kullanmanız durumunda derleyici/donanım sizin için her şeyi yapar; bu nedenle, seçeneğiniz varsa bunu yapmanız gerekir.

+0

Neye niyet ettiğim buydu ... ama aniden merak ettim: 'x * x '' imzasız 'durumuna uyup uymadığını bilmiyoruz ve sonuca ne gibi bir yuvarlama uygulanması gerektiğini belirsiz ... –

+0

@ MatthieuM .: Ama önemi yok. Biz sadece (x * x) >> (half_bits * 2) 'ile ilgileniyoruz. Uygun kaydırmayla, doğru sonucu almak için yukarıdaki şartları kullanabiliriz. –

+0

'n' bitlerini kullanarak' x_div' 'n/2' bit'lerine sahip olacaktır. 'N' bitlerinde saklanan maksimum değer' 2^n - 1'. Çünkü (2^n -1) - (2^(n/2) -1) * (2^(n/2) -1) 'her zaman sıfırdan büyüktür, biliyoruz ki x_div * x_div' asla taşma 'n' bitleri. –

-4

"y" için TYPE int kullanın. Sanırım bu amacı çözecek.

+0

Not: Yanlış cevaplarınızı SO'da silmenin yanlış bir tarafı yoktur ve 4 downvot'u hızlı bir şekilde almanız genellikle cevabın yanlış olduğunu göstermez, eğer downvot'ların hiçbiri bir açıklama bırakmaktan rahatsız olsa bile. – hyde

+0

@hyde: Eh, bir açıklama bu kesinlikle "amacı çözmez";) –

+0

@OliCharlesworth evet, kesinlikle düşüş notları yanlış olduğu anlamına gelmez. Sadece "cevabın sadece ... yanlış" olsa bile, oy verdiğinde yorum bırakmayı tercih eden kampta yaşıyorum. – hyde