float a=1/2; //a=0.00
欲得到正確的運算結果 0.50 必須這樣 :
float a=1.0/2; //至少一個運算元是用浮點數表示
float a=1/2.0; //至少一個運算元是用浮點數表示
float a=(float)1/2; //被除數強制轉型為浮點數
複雜的數學運算例如三角函數, 指數或對數等超越函數就要用到 Arduino C 語言內建的數學函數, 參考官方文件中的 Math 與 Trigonometry 部分 :
# https://www.arduino.cc/en/Reference/HomePage
Arduino 官方文件中的數學函數列表 (含三角函數) :
數學函數 | 說明 |
abs(x) | 傳回 x 的絕對值 |
min(x,y) | 傳回 x 與 y 兩數中值較小者 |
max(x,y) | 傳回 x 與 y 兩數中值較大者 |
constrain(x,min,max) | 以 max, min 為上下限, 傳回 x 值 |
pow(x,y) | 傳回 x 的 y 次方 |
sqrt(x) | 傳回 x 的平方根 |
floor(x) | 傳回不大於 x 的最大整數 |
ceil(x) | 傳回不小於 x 的最小整數 |
sin(x) | 傳回 x 的正弦值 |
cos(x) | 傳回 x 的餘弦值 |
tan(x) | 傳回 x 的正切值 |
random(max) | 傳回 0~(max-1) 間的隨機數 |
random(min,max) | 傳回 min~(max-1) 間的隨機數 |
randomSeed(x) | 啟始一個假隨機數產生器, x 為整數 |
除了官網的所列的數學函數外, 其實 C 語言的其他數學函數也可以用, 例如自然對數 log, 常用對數 log10, 雙曲函數 sinh, cosh, tanh 等 (但 fmod 不行), 參考 :
# C 教材:數學函式庫
其他數學函數 | 說明 |
fabs(x) | 傳回浮點數 x 的絕對值 |
asin(x) | 傳回 x 的反正弦值 sin-1 |
acos(x) | 傳回 x 的反餘弦值 cos-1 |
atan(x) | 傳回 x 的反正切值 tan-1 |
sinh(x) | 傳回 x 的雙曲正弦值 (ex-e-x)/2 |
cosh(x) | 傳回 x 的雙曲餘弦值 (ex+e-x)/2 |
tanh(x) | 傳回 x 的雙曲正切值 sinh(x)/cosh(x) |
exp(x) | 傳回 x 的自然指數值 ex |
log(x) | 傳回 x 的自然對數值 ln(x) |
log10(x) | 傳回 x 的常用對數值 log10(x) |
ldexp(x,n) | 傳回 x 與 2 的 n 次方乘積 x*2n |
另外, AVR 晶片系列也定義了一些常用的數學常數 (Macro, 巨集), 都可以在 Arduino 程式中使用, 參考 :
# http://www.nongnu.org/avr-libc/user-manual/group__avr__math.html
# http://wiki.secondlife.com/wiki/RAD_TO_DEG
# http://wiki.secondlife.com/wiki/DEG_TO_RAD
數學常數 | 說明 |
M_E | e=2.7182818284590452354 (自然指數) |
M_LOG2E | log2e=1.4426950408889634074 (自然指數以 2 為底之對數) |
M_LOG10E | log10e=0.43429448190325182765 (自然指數的常用對數) |
M_LN2 | ln2=0.69314718055994530942 (2 的自然對數) |
M_LN10 | ln10=2.30258509299404568402 (10 的自然對數) |
M_PI | PI=3.14159265358979323846 (圓周率) |
M_PI_2 | PI/2=1.57079632679489661923 (二分之一的圓周率) |
M_PI_4 | PI/4=0.78539816339744830962 (四分之一的圓周率) |
M_1_PI | 1/PI=0.31830988618379067154 (圓周率的倒數) |
M_2_PI | 2/PI=0.63661977236758134308 (兩倍的圓周率倒數) |
M_2_SQRTPI | 2/sqrt(PI)=1.12837916709551257390 (2 除以圓周率開平方) |
M_SQRT2 | sqrt(2)=1.41421356237309504880 (2 開平方) |
M_SQRT1_2 | 1/sqrt(2)=0.70710678118654752440 (2 開平方的倒數) |
DEG_TO_RAD | 角度*PI/180=0.0174532925199432958 (角度轉弧度常數) |
RAD_TO_DEG | 弧度*180/PI=57.2957795130823208768 (弧度轉角度常數) |
NAN | 非數字=nan |
INFINITY | 無限大=inf |
測試範例 (使用 Nano) :
void setup() {
Serial.begin(9600);
Serial.println(abs(-1)); //輸出 1
Serial.println(abs(-1.235)); //輸出 1.23
Serial.println(fabs(-1.235)); //輸出 1.23
Serial.println(min(-1,-3)); //輸出 -3
Serial.println(max(-1,1)); //輸出 1
Serial.println(constrain(101,100,200)); //輸出 100
Serial.println(constrain(150,100,200)); //輸出 150
Serial.println(constrain(201,100,200)); //輸出 200
Serial.println(constrain(201,100,200)); //輸出 200
Serial.println(pow(2,3)); //輸出 8.00
Serial.println(sqrt(2)); //輸出 1.41
Serial.println(floor(1.9)); //輸出 1.00
Serial.println(floor(-1.1)); //輸出 -2.00
Serial.println(ceil(1.9)); //輸出 2.00
Serial.println(ceil(-1.1)); //輸出 -1.00
float deg=30;
float rad=deg*PI/180;
Serial.println(sin(rad)); //輸出 0.50
Serial.println(sin(deg*DEG_TO_RAD)); //輸出 0.50
Serial.println(cos(rad)); //輸出 0.87
Serial.println(cos(deg*DEG_TO_RAD)); //輸出 0.87
Serial.println(tan(deg*DEG_TO_RAD)); //輸出 0.58
//轉回角度
Serial.println(asin(0.5)*RAD_TO_DEG); //輸出 30.00
Serial.println(acos(0.87)*RAD_TO_DEG); //輸出 29.54
Serial.println(atan(0.58)*RAD_TO_DEG); //輸出 30.11
Serial.println(atan2(5.8,10)*RAD_TO_DEG); //輸出 30.11
Serial.println(sinh(1)); //輸出 1.18
Serial.println(cosh(1)); //輸出 1.54
Serial.println(tanh(1)); //輸出 0.76
Serial.println(exp(1)); //輸出 2.72
Serial.println(log(2)); //輸出 0.69
Serial.println(log10(100)); //輸出 2.00
Serial.println(ldexp(2,3)); //輸出 16.00
Serial.println(M_E,19); //輸出 2.7182817459106445312
Serial.println(M_LOG2E,19); //輸出 1.4426950454711914062
Serial.println(M_LOG10E,19); //輸出 0.4342945098876953125
Serial.println(M_LN2,19); //輸出 0.6931471824645996093
Serial.println(M_LN10,19); //輸出 2.3025851249694824218
Serial.println(M_PI,19); //輸出 3.1415927410125732421
Serial.println(M_PI_2,19); //輸出 1.5707963943481445312
Serial.println(M_PI_4,19); //輸出 0.7853981971740722656
Serial.println(M_1_PI,19); //輸出 0.3183098793029785156
Serial.println(M_2_PI,19); //輸出 0.6366197586059570312
Serial.println(M_2_SQRTPI,19); //輸出 1.1283792257308959960
Serial.println(M_SQRT2,19); //輸出 1.4142135620117187500
Serial.println(M_SQRT1_2,19); //輸出 0.7071067810058593750
Serial.println(DEG_TO_RAD,19); //輸出 0.0174532914161682128
Serial.println(RAD_TO_DEG,19); //輸出 57.2957801818847656250
Serial.println(NAN); //輸出 nan
Serial.println(INFINITY); //輸出 inf
Serial.println(random(10)); //輸出 0~10 間之隨機數
Serial.println(random(100,200)); //輸出 100~200 間之隨機數
randomSeed(1023);
}
void loop() {
Serial.println(random(10)); //輸出 0~10 間之隨機數
delay(1000);
}
結果似乎在小數點後第五位就有誤差了 (雖然不需要這麼精確), 即使是常數也是如此, 不知是何原因?
關於超越函數詳參 :
# 維基 : 三角函數
# 維基 : 指數函數
# 維基 : 對數
# 維基 : 自然對數
# 維基 : 雙曲函數
# 維基 : 反雙曲函數
沒有留言:
張貼留言