簡體   English   中英

32位整數縮放,無溢出

[英]32bit integer scaling with no overrun

嗨,我有以下值:

uint32_t value = 1230000;
uint32_t max_value = 1234567;

現在,我想執行縮放:

uint32_t scaled = value * 1000000 / max_value;

問題是,如果我使用32位整數,那么對於這么大的數字它將溢出。 另一方面,我不能使用64位。 任何想法如何正確實現上述縮放?

編輯

值得一提的是,我正在研究STM32(32位微控制器),在其中執行64位乘法和除法非常昂貴。 因此,我想避免它們。

您可以通過將scale作為一個以1000為底的數字來實現: value = value_high*1000 + value_low 分別計算value_highvalue_low對比例的貢獻,將中間值存儲為分數: scaled = scaled_int + scaled_remainder/max_value

uint32_t value_low = value%1000;
uint32_t value_high = value/1000;
uint32_t scaled_int, scaled_remainder;

uint32_t low = value_low * 1000000;
scaled_int = low / max_value;
scaled_remainder = low % max_value;

scaled_int += value_high * 810;  // pre-calculated 1000*1000000 / max_value
scaled_remainder += value_high * 730;  // pre-calculated 1000*1000000 % max_value
scaled_int += scaled_remainder / max_value;
scaled_remainder = scaled_remainder % max_value;

此外,您不必使用以1000為基數,以1024為基數可能會更快一些。 只要第4行和第8行不溢出其最大值,它就應該起作用。

您可以將scaled聲明為unsigned long long類型,如下所示,然后進行相應的顯式類型轉換。

unsigned long long scaled = (unsigned long long)value * 1000000 / max_value; /* make either operand of unsigned long long type explicitly */
printf("%llu\n",scaled);

如果您的翻譯器可以支持64位,則

uint32_t scaled =(uint32_t)((uint64_t)value * 1000000 / max_value);

如果支持浮動,則

uint32_t scaled =(uint32_t)(value *1.0 / max_value* 1000000);

會有一點精度損失。

最快的縮放方法是使用2個功率縮放因子。

即使您有兩個使用不同比例因子縮放的數字-該算法也是微不足道的。

例:

uint32_t scaledDiv(uint32_t a, uint32_t b, uint32_t *sclef)
{
    *sclef = __builtin_clz(a);
    a <<= *sclef;
    return a/b;
}

問題的形式為: value/max_1 = x/1000000

無需以封閉形式求解此問題,就可以使用二等分迭代地計算最接近的x

 uint32_t step=max_value>>1;
 uint32_t v=0, x=0, step2=1000000/2 << 12;
 // step2 has been scaled to add extra precision
 while(step) {
    if (value > v+step) { v+=step; x+=step2; }
    step>>=1; step2>>=1;
 }
 x=(x+2048)>>12; // scale down and round

結果將在32次迭代中完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM