一、函數說明
對 double 而言,取整、取余的相關函數和運算符請參考下表:
VB6.0 |
C |
C# |
說 明 |
Int(x) |
floor(x) |
Math.Floor(x) |
floor表示地板,也就是將 Math.Floor(1.9) 返回 1 Math.Floor(1.0) 返回 1 Math.Floor(-1.0) 返回 -1 Math.Floor(-1.3) 返回 -2 Math.Floor(-1.9) 返回 -2 |
ceil(x) |
Math.Ceiling(x) |
ceil表示天花板,也就是將 Math.Ceiling(1.9) 返回 2 Math.Ceiling(1.3) 返回 2 Math.Ceiling(1.0) 返回 1 Math.Ceiling(-1.0) 返回 -1 Math.Ceiling(-1.9) 返回 -1 |
|
Fix(x) |
Math.Truncate(x) |
表示取 Math.Truncate(1.9) 返回 1 Math.Truncate(1.0) 返回 1 Math.Truncate(-1.0) 返回 -1 Math.Truncate(-1.9) 返回 -1 |
|
Round(x) |
Math.Round(x,...) |
表示四舍五入,如:四舍五入取整 Math.Round(1.9) 返回 2 Math.Round(1.5) 返回 2 Math.Round(1.3) 返回 1 Math.Round(1.0) 返回 1 Math.Round(-1.0) 返回 -1 Math.Round(-1.3) 返回 -1 Math.Round(-1.5) 返回 -2 Math.Round(-1.9) 返回 -2 |
|
x Mod y |
fmod(x,y) |
x % y |
返回 x / y 的余數,其符號與 x 一致。 C語言里 % 只能用於整型變量 注意:VB6.0會對結果四舍五入取整 |
x / y |
x / y |
x / y |
返回 x / y,對於整數而言,將舍去小數部分。 |
1、詳述Math.Round
Math.Round 還有更豐富的功能
①精確到小數點后n位
如:Math.Round(x,n) 表示對 x 只取小數點后 n 位,多余部分四舍五入。
②四舍五入問題
四舍是一定的,但對於五到底入還是不入呢?Math.Round是可以通過MidpointRounding來進行控制的。
MidpointRounding.AwayFromZero 表示五入,這是默認的方法,如:
Math.Round(1.5,MidpointRounding.AwayFromZero); 返回 2
Math.Round(-1.5,MidpointRounding.AwayFromZero); 返回 -2
MidpointRounding.ToEven 就比較有意思了,如果5前面的數字是奇數則入,否則就舍去。如:
Math.Round(2.5,MidpointRounding.ToEven); 返回 2
Math.Round(1.5,MidpointRounding.ToEven); 返回 2
Math.Round(-1.5,MidpointRounding.ToEven); 返回 -2
Math.Round(-2.5,MidpointRounding.ToEven); 返回 -2
二、函數關系
1、floor和ceil的關系
floor(x) = -ceil(-x),同樣的ceil(x)=-floor(-x)。VB6.0里沒有ceil函數,就可以用 -Int(-x) 來代替。
2、Math.Truncate 和floor、ceil的關系
Math.Truncate(x) =
寫成C語言代碼就是
double Truncate(double x)
{
if(x >= 0.0)
{
return floor(x);
}
return ceil(x); //或-floor(-x)
}
三、應用
1、歸化角度
如:手表的秒針1分鍾走1圈。
分鍾之后,它與起始位置的夾角是多少?顯然這個角度等於
度。現在要把這個角度歸化到
之間。即找到一個整數
,使得
成立。只考慮不等式的左半部分,則有
,即
。顯然這個夾角應該是
。
同樣的,判斷經度
是否在經度
和經度
之間(只考慮劣弧,不考慮優弧),不能使用
。如:經度180在經度-179和經度179之間,但它不滿足-179 < 180 < 179。應該使用下式判斷
函數Angle360(x)將返回角度
(n是一個整數),且返回值在
之間。顯然
,因此Angle360函數的C代碼如下:
double Angle360(double x)
{
return x - floor(x / 360.0) * 360.0;
}
2、擴展fmod函數
上述問題里,將角度
歸化到
之間可以使用fmod(360.0 * x,360.0);(C#里可以使用(360.0 * x) % 360.0)。但是,使用fmod感覺不太方便——它的返回值符號與第一個參數的符號相同。也就是說 x 小於零,則返回值將在
之間。因此有必要擴展fmod函數。
fmod(x,y)的實質是找到合適的整數
,使得
,然后返回余數
。
如果需要余數
,則
如果需要余數
,則
如果需要求絕對值最小的余數,則
。
fmod函數的模擬代碼如下
double fmod(double x,double y)
{
y = fabs(y);
if(x >= 0.0)
{
y = x - y * floor(x / y);
}
else
{
y = x - y * ceil(x / y);
}
return y;
}
fmod函數的擴展代碼如下
/****************************************************************\
求 x / y 的余數
nFlag [in] 1 返回的余數大於等於零
-1 返回的余數小於等於零
2 返回絕對值最小的余數,若同時出現 ±(y / 2) 則取正值
-2 返回絕對值最小的余數,若同時出現 ±(y / 2) 則取負值
0 與 2 相同
\****************************************************************/
double fmodEx(double x,double y,int nFlag)
{
y = fabs(y);
if(nFlag < -2)
{
nFlag = -2;
}
else if(nFlag > 2)
{
nFlag = 2;
}
switch(nFlag)
{
case 1://返回的余數大於等於 0
y = x - y * floor(x / y);
break;
case -1://返回的余數小於等於 0
y = x - y * ceil(x / y);
break;
case -2://返回的絕對值最小的余數,優先考慮 - y / 2
y = x - y * floor(x / y + 0.5);
break;
default://返回的絕對值最小的余數,優先考慮 + y / 2
y = x - y * ceil(x / y - 0.5);
break;
}
return y;
}
3、格點
現在要在區間
之間插入若干點
,其中n是一個整數,d是一段固定的距離(只考慮正值),如:100米、1000米……
計算
的時候要注意,不要寫 for(double n = ceil(a/d);n <= floor(b/d);n++) 這樣的代碼,因為double是有誤差的,這樣會導致誤差積累。應該這樣:
double n0 = ceil(a/d);
double x0 = n0 * d;
int nMax = (int)(floor(b/d) - n0 + 0.1);
double x;
for(int i = 0;i <= nMax;i++)
{
x = x0 + i * d;
}
下面的函數專門用來獲取格點
/**********************************************************\
獲取區間[a,b]之間的格點,格點坐標是 d 的整數倍
x0 [out] 返回起始格點。
若 d 大於零,x0 是坐標最小的格點
若 d 小於零,x0 是坐標最大的格點
返回:獲得格點的個數 nCount
格點坐標為 x0 + n * d。n = 0,1,2,...nCount - 1
\**********************************************************/
long GetLatticePoints(double a,double b,double d,double*x0)
{
long nCount = 0; //格點個數
double nMin; //n 的最小值
double nMax; //n 的最大值
a /= d;
b /= d;
if(a > b)
{
double t;
t = a;
a = b;
b = t;
}
nMin = ceil(a);
nMax = floor(b);
if(nMax >= nMin)
{
nCount = (long)(nMax - nMin + 1.1);
if(x0)
{
*x0 = nMin * d;
}
}
return nCount;
}

向下取整數,即返回最大的整數
使得
向上取整數,即返回最小的整數
使得
的整數部分