**定點數** = 整數 × 固定縮放因子 (Scale Factor)
// 需求:計算半徑 6 的圓周長 C = 2 * π * r
// π 放大 100 倍 = 314
int r = 6;
int pi_scaled = 314; // 3.14 * 100
int scale = 100;
// 運算全在整數域
int circumference_scaled = 2 * r * pi_scaled; // 2 * 6 * 314 = 3768
int circumference = circumference_scaled / scale; // 3768 / 100 = 37 (截斷)
// 改進:四捨五入 (加半個 scale 再除)
int circumference_rounded = (circumference_scaled + scale / 2) / scale; // (3768 + 50) / 100 = 38
// 真實值 37.68,四捨五入 38,誤差 0.32
// 縮放因子 256 = 2^8,除法 = 右移 8 位
int SCALE = 256;
int SCALE_SHIFT = 8;
// π ≈ 3.14159 * 256 ≈ 804
int PI_FIXED = 804;
int r = 6;
// 2 * r * PI_FIXED = 2 * 6 * 804 = 9648
int result_fixed = (2 * r * PI_FIXED) >> SCALE_SHIFT; // 9648 >> 8 = 37
// 四捨五入:加 128 (SCALE/2) 再右移
int result_rounded = (2 * r * PI_FIXED + (SCALE >> 1)) >> SCALE_SHIFT; // (9648 + 128) >> 8 = 38
public class FixedPointMath {
// 縮放因子 1000 (支援 3 位小數,十進制友好)
public static final int SCALE = 1000;
public static final int HALF_SCALE = 500;
// 常用常數 (已縮放)
public static final int PI = 3142; // 3.142
public static final int PI_DIV_2 = 1571; // 1.571
public static final int PI_DIV_4 = 785; // 0.785
public static final int E = 2718; // 2.718
public static final int SQRT_2 = 1414; // 1.414
public static final int DEG_TO_RAD = 17; // 0.01745... (實際 17.45,此處簡化)
/** 整數轉定點數 */
public static int toFixed(int i) {
return i * SCALE;
}
/** 定點數轉整數 (截斷) */
public static int toInt(int fixed) {
return fixed / SCALE;
}
/** 定點數轉整數 (四捨五入) */
public static int toIntRounded(int fixed) {
return (fixed + (fixed >= 0 ? HALF_SCALE : -HALF_SCALE)) / SCALE;
}
/** 定點數加法 */
public static int add(int a, int b) {
return a + b;
}
/** 定點數減法 */
public static int sub(int a, int b) {
return a - b;
}
/** 定點數乘法 (結果需除以 SCALE) */
public static int mul(int a, int b) {
// 防溢位:長整數中間運算
return (int)(((long)a * b) / SCALE);
}
/** 定點數除法 (被除數先乘 SCALE) */
public static int div(int a, int b) {
if (b == 0) throw new ArithmeticException("Division by zero");
return (int)(((long)a * SCALE) / b);
}
/** 定點數平方根 (牛頓迭代法,整數版) */
public static int sqrt(int a) {
if (a <= 0) return 0;
int x = a;
int y = (x + div(a, x)) >> 1;
while (y < x) {
x = y;
y = (x + div(a, x)) >> 1;
}
return x;
}
/** 定點數正弦 (查表法 + 線性插值,極快) */
private static final int[] SIN_TABLE = {
0, 175, 349, 523, 698, 872, 1045, 1219, 1392, 1564, 1736, 1908,
2079, 2250, 2419, 2588, 2756, 2924, 3090, 3256, 3420, 3584, 3746, 3907,
4067, 4226, 4384, 4540, 4695, 4848, 5000, 5150, 5299, 5446, 5592, 5736,
5878, 6018, 6157, 6293, 6428, 6561, 6691, 6820, 6947, 7071, 7193, 7314,
7431, 7547, 7660, 7771, 7880, 7986, 8090, 8192, 8290, 8387, 8480, 8572,
8660, 8746, 8829, 8910, 8988, 9063, 9135, 9205, 9272, 9336, 9397, 9455,
9511, 9563, 9613, 9659, 9703, 9744, 9781, 9816, 9848, 9877, 9903, 9925,
9945, 9962, 9976, 9986, 9994, 9998, 10000
}; // 0~90 度,值已 * 10000
public static int sin(int deg) {
// 正規化至 0~360
deg = deg % 360;
if (deg < 0) deg += 360;
int sign = 1;
if (deg > 180) {
deg -= 180;
sign = -1;
}
if (deg > 90) {
deg = 180 - deg;
}
// 線性插值
int idx = deg;
int val = SIN_TABLE[idx];
if (idx < 90) {
int nextVal = SIN_TABLE[idx + 1];
val += (nextVal - val) * (deg % 1); // 整數度無小數部,此處為 0
}
return (val * sign) / 10; // 轉換為 *1000 縮放
}
/** 定點數餘弦 */
public static int cos(int deg) {
return sin(deg + 90);
}
}
public class GamePhysics {
// 位置、速度、加速度皆用定點數 (單位:像素 * 1000)
int x = FixedPointMath.toFixed(100); // 100.000 像素
int vx = FixedPointMath.toFixed(50); // 50.000 px/幀
int ax = 0;
public void update() {
// v = v + a
vx = FixedPointMath.add(vx, ax);
// x = x + v
x = FixedPointMath.add(x, vx);
}
public int getScreenX() {
return FixedPointMath.toIntRounded(x); // 繪製時取整數像素
}
// 發射角度 45 度,速度 100
public void shoot(int angleDeg, int speed) {
int rad = FixedPointMath.mul(angleDeg, FixedPointMath.DEG_TO_RAD);
// 簡化:直接用查表 sin/cos (度數版)
vx = FixedPointMath.mul(speed, FixedPointMath.cos(angleDeg));
int vy = FixedPointMath.mul(speed, FixedPointMath.sin(angleDeg));
}
}
若專案大量浮點運算,建議引入 **MathFP** (JavaME 定點數學庫):
// MathFP 使用範例
import org.mathfp.FP;
FP x = FP.fromInt(10);
FP y = FP.fromInt(3);
FP z = FP.div(x, y); // 3.333...
FP sin = FP.sin(FP.PI_DIV_4); // sin(45°) ≈ 0.707
CLDC 1.0 無浮點數不是阻礙,而是**倒逼工程師理解數值計算本質**的機會。定點數運算核心:**整數運算 + 固定縮放因子 + 手動小數點管理**。掌握此技術,不僅能在 J2ME/嵌入式/舊平台開發中遊刃有餘,更能深入理解:
**工程智慧:在約束中尋找通用原理,而非抱怨工具不足。**