2012-01-14 32 views
5

Özellikle: İki işaretsiz tam bilgisi, (a, b) ve l (a * b) hesaplamak istiyor% UINT_MAX (UINT_MAX maksimal işaretsiz int olarak tanımlanmaktadır). Bunu yapmanın en iyi yolu nedir?Modülo çarpma

Arkaplan: Geometrik bir öyküyü öykünecek bir modül yazmak zorundayım, bir sonraki öğeyi (modulo UINT_MAX) verecek olandan okuyordum, bulduğum tek çözüm geçerli öğeyi kendi zamanlarına eklemek. aşağıdaki mantık kullanılarak yapılır eklenirken. (I aritmetik dizisi için kullanan) current_value =

for(int i=0; i<b; ++i){ 
    if(UINT_MAX - current_value > difference) { 
    current_value += difference; 
    } else { 
    current_value = difference - (UINT_MAX - current_value); 
    } 

birinci tekrarda bir (her yineleme güncelleme ve fark (her zaman = ve) Açıkçası bu bir akıllı bir çözüm değildir. akıllı bir kişi bunu başarmak istiyorum nasıl ?

Teşekkürler! bahsedildiği gibi mevcut iki katı genişlikte bir türü varsa

+1

Modül operatörü veya 8 bayt tamsayı türlerini kullanamaz mısınız? – davogotland

+1

"Uzun uzun" için çok basit bir aptal çözüm int'den daha uzun bir tiptir. uzun uzun sonuç = ((uzun uzun) a) * ((uzun uzun) b)% ((uzun uzun) UINT_MAX); –

+0

@JoachimIsaksson sonuçta, o zamana kadar uzun bir süre olmamalıdır, değil mi? – davogotland

cevap

2

, sadece int 32 bit ve long long 64 (veya daha fazla) olduğu

(unsigned int)(((unsigned long long)a * b) % UINT_MAX) 

burada, bunu kullanın. Daha büyük bir türünüz yoksa, faktörleri bit-yarısının yarısına bölebilir, parçaları çoğaltabilir ve azaltabilirsiniz, sonunda birleştirin. Burada 32-bit işaretsiz için resimli: Elbette

a_low = a & 0xFFFF; // low 16 bits of a 
a_high = a >> 16; // high 16 bits of a, shifted in low half 
b_low = b & 0xFFFF; 
b_high = b >> 16; 
/* 
* Now a = (a_high * 65536 + a_low), b = (b_high * 65536 + b_low) 
* Thus a*b = (a_high * b_high) * 65536 * 65536 
*   + (a_high * b_low + a_low * b_high) * 65536 
*   + a_low * b_low 
* 
* All products a_i * b_j are at most (65536 - 1) * (65536 - 1) = UINT_MAX - 2 * 65536 + 2 
* The high product reduces to 
* (a_high * b_high) * (UINT_MAX + 1) = (a_high * b_high) 
* The middle products are a bit trickier, but splitting again solves: 
* m1 = a_high * b_low; 
* m1_low = m1 & 0xFFFF; 
* m1_high = m1 >> 16; 
* Then m1 * 65536 = m1_high * (UINT_MAX + 1) + m1_low * 65536 = m1_high + m1_low * 65536 
* Similar for a_low * b_high 
* Finally, add the parts and take care of overflow 
*/ 
m1 = a_high * b_low; 
m2 = a_low * b_high; 
m1_low = m1 & 0xFFFF; 
m1_high = m1 >> 16; 
m2_low = m2 & 0xFFFF; 
m2_high = m2 >> 16; 
result = a_high * b_high; 
temp = result + ((m1_low << 16) | m1_high); 
if (temp < result) // overflow 
{ 
    result = temp+1; 
} 
else 
{ 
    result = temp; 
} 
if (result == UINT_MAX) 
{ 
    result = 0; 
} 
// I'm too lazy to type out the rest, you get the gist, I suppose. 

, ne gerek @Toad varsayar olarak, o unsigned int çarpımı tıpkı buydu aslında azaltma modülo UINT_MAX + 1 ise.

+2

İmzasız uzun uzun mod MAX_INT azaltma denklemin uygulanması (a * N + b)% (N-1) = (a + b)% (N-1). –

+0

Doğru, ancak a + b'nin taşması durumunda ayarlamalısınız. Daha büyük bir tip mevcutsa, yukarı ve aşağı döküm, ürünü yüksek ve düşük bitlere ayırmadan sorunu çözer, bu da kavramsal olarak daha basittir. –

+0

Kavramsal olarak daha basit olduğunu kabul etti, ancak hile, gerçekten de pahalı bir çift kelime bölünmesinden kaçınıyor –

0

DÜZENLEME: Yorumlarda belirtildiği gibi ... bu cevap Modulo MAX_INT + 1 için geçerlidir. Burada ileride başvurmak üzere burada duracağım.

Ondan çok daha simpeler var:

Sadece iki in imzasız çarpın, sonuç da işaretsiz int olacak. İmzasız int'e uymayan her şey temelde orada değildir.

See example here

#include <stdio.h> 

void main() 
{ 
    unsigned int a,b; 
    a = 0x90000000; 
    b = 2; 

    unsigned int c = a*b; 

    printf("Answer is %X\r\n", c); 
} 

cevap: Bir modülo işlemi yapmak Yani gerek 0x20000000 (yani 0x120000000 olmalıydı ama cevap kesildi, sen modülo işlemiyle sadece istediğini)

+2

Soruyu ilk yanıtla birlikte yanlış okumanıza benziyor. (ki şimdi silinmiştir) OP, UINT_MAX + 1' değil, modulo 'UINT_MAX' istiyor. – Mysticial

+0

ah .... Bu durumda uzun uzun tip kullanmanız gerekiyor – Toad

İlgili konular