在浮點線性插值中,一位用戶提出了以下實作lerp:
float lerp(float a, float b, float f)
{
return (a * (1.0 - f)) (b * f);
}
而另一個用戶提出了這個實作lerp:
float lerp(float a, float b, float f)
{
return a f * (b - a);
}
顯然,由于浮點精度損失,后一種實作方式較差。
然后我查看了維基百科,它說的是以前的實作:
// Precise method, which guarantees v = v1 when t = 1. This method is monotonic only when v0 * v1 < 0.
// Lerping between same values might not produce the same value
對于后者:
// Imprecise method, which does not guarantee v = v1 when t = 1, due to floating-point arithmetic error.
// This method is monotonic. This form may be used when the hardware has a native fused multiply-add instruction.
這給了我幾個問題:
維基百科指出“相同值之間的 Lerping 可能不會產生相同的值”我認為除了浮點精度之外,功能是相同的。不是嗎
(a * (1.0 - f)) (b * f)=a f * (b - a)一個數學恒等式?
如果不是,那么在兩個函式中會產生不同結果的值是什么?
維基百科所說的單調是什么意思?為什么一種實作是單調的,而另一種不是?
還有其他常見的實作
lerp嗎?
編輯: 如果后一種實作存在浮點不精確問題,但速度并不快,為什么它甚至存在?
uj5u.com熱心網友回復:
維基百科指出“相同值之間的 Lerping 可能不會產生相同的值”我認為除了浮點精度之外,功能是相同的。不是嗎
(a * (1.0 - f)) (b * f)=a f * (b - a)一個數學恒等式?
如果不是,那么在兩個函式中會產生不同結果的值是什么?
a ? (1.0? f ) ( b ? f ) = a f ? ( b ? a ) 是一個數學恒等式,但計算的結果a*(1.0-f) b*f并不總是等于計算的結果a f*(b-a)。
例如,考慮具有十進制基數和有效數中的三位數字的浮點格式。a設為 123,b為 223,f 為 0.124 。
然后1.0-f是 0.876。然后a * .876將得到實數算術結果 107.748,但由于必須將結果四舍五入為三位有效數字,因此會產生 108。對于b * f,我們會得到 27.652,但會產生 27.7。然后108 27.7會產生 135.7 但會產生 136。
在另一邊,b-a產生 100。然后f*100產生 12.4。然后a 12.4會產生 135.4 但會產生 135。
所以左右兩邊136和135的計算結果是不相等的。
- 維基百科所說的單調是什么意思?
如果更大的引數產生更大的結果,則函式 f( x ) 是嚴格遞增的: x 0 < x 1意味著 f( x 0 ) < f( x 1 )。如果x 0 < x 1意味著 f( x 0 ) ≤ f( x 1 ),則它是弱上升的。如果x 0 < x 1意味著 f( x 0 ) > f( x 1 ) 或 f( x 0 ) ≥ f( x 1 ,則它是嚴格或弱下降的), 分別。如果函式嚴格升序或嚴格降序,則該函式是嚴格單調的。如果它是弱上升或弱下降,則它是弱單調的。
當一個函式被稱為單調時,作者的意思是它是嚴格單調的或弱單調的,但是如果沒有背景關系或明確的陳述,就不清楚哪個。在浮點算術的背景關系中,通常意味著弱單調性,因為浮點舍入通常會破壞強單調性。
在這種用法中,維基百科意味著,當被視為 的函式時t,v0 t * (v1 - v0)是單調的,(1 - t) * v0 t * v1而不是單調的。
為什么一種實作是單調的,而另一種不是?
要了解為什么v0 t * (v1-v0)是單調的,請考慮將v1-v0其固定為t變化。然后t * (v1-v0)是t * c一些常數c。t由于浮點舍入的性質,這是單調的:如果t增加,則增加的實數算術結果t * c(對于正數c;對于負數有一個對稱引數c),并且它必須四舍五入的數字保持不變或增加。例如,如果我們四舍五入為整數并考慮 3、3.1、3.2、3.3、3.4 等等,這些都將四舍五入為 3。然后 3.5 舍入為 4(使用四舍五入到最接近,平到)、3.6 輪到 4 輪,以此類推。舍入的結果總是隨著引數的增加而增加;它是單調的。所以浮點乘法是單調的。
類似地,浮點加法是單調的;v0 d總是隨著增加而d增加。v0 t * (v1-v0)單調也是如此。
在(1-t) * v0 t * v1中,1-t是單調的,但它是下降的。所以現在我們將一個降序函式 , 添加(1-t) * v0到一個升序函式 , t * v1。這為降序函式跳轉到一個新值但升序函式沒有或沒有那么多的機會打開了大門。對于我們的三位數格式,例如v0= 123、v1= 223 和t= .126 或 .127:
t= .126 |
t= .127 |
|
|---|---|---|
1-t |
.874 | .873 |
(1-t) * v0 |
107.502 → 108 | 107.379 → 107 |
t * v1 |
28.098 → 28.1 | 28.321 → 28.3 |
(1-t) * v0 t * v1 |
136.1 → 136 | 135.3 → 135 |
- 還有其他常見的實作
lerp嗎?
正如njuffa在評論中指出的那樣,一些實作可能使用融合乘法加法,它計算a ? b c時只有一個舍入誤差,而乘法的舍入誤差和加法的舍入誤差不同。這種操作是在標準 C 庫例程中定義的fma,盡管在沒有硬體支持的平臺上它可能會很慢。所以線性插值可以計算為fma(t, v1, fma(-t, v0, v0)),名義上計算t*v1 (-t*v0 v0)。
從代數上講,這相當于t*v1 (1-t)*v0,但我手頭沒有任何關于此fma計算產生的數學性質的評論。
如果后一種實作存在浮點不精確問題,但速度并不快,為什么它還存在呢?
兩種方法都會遇到浮點舍入問題。有問題,當為 1 時v0 t * (v1 - v0)可能不相等,因為 中可能出現舍入誤差,所以不恢復。另一個有可能不是單調的問題,如上圖。v1tv1 - v0v0 (v1 - v0)v1
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/495359.html
下一篇:嘗試在特定區域從右到左添加字串
