CLDC 1.0 移除 float/double 以減小 VM 體積。若需浮點運算 (物理模擬、3D、GPS 計算),有三條路:
int bits 為符號/指數/尾數,通用但慢本文提供後兩者實現代碼與效能分析。
將 32-bit int 視為 IEEE 754 二進制佈局:
值 = (-1)^S × 1.M × 2^(E-127)
/**
* 將 IEEE 754 int bits 轉為 整數部分 + 小數部分(放大1000倍)
* @param bits 32-bit IEEE 754 表示
* @param precision 0=小數3位(×1000), 1=小數2位(×100) 等
* @return int[2] { 整數部分, 小數部分(已放大) }
*/
public static int[] intBitsToFloat(int bits, int precision) {
// 1. 符號
int sign = (bits >> 31) & 1;
// 2. 指數 (無偏移)
int exp = ((bits >> 23) & 0xFF) - 127;
// 3. 尾數 (含隱含位 1)
int mantissa = (bits & 0x7FFFFF) | 0x800000; // 23 bits + 隱含 1 = 24 bits
// 4. 根據指數左移/右移尾數對齊二進制小數點
if (exp >= 0) mantissa <<= exp; // 整數部分增大
else mantissa >>= -exp; // 變為小數
// 5. 分離整數與小數 (以 2^23 為單位)
int intPart = mantissa >> 23;
int fracPart = mantissa & 0x7FFFFF; // 剩餘 23 bits 為小數
// 6. 小數轉十進制 (放大 precision 指定倍數)
int scale = (precision == 0) ? 1000 : 100; // 可擴充
long fracScaled = (fracPart * (long)scale) >> 23; // 定點數乘法再歸一化
// 7. 符號處理
if (sign == 1) { intPart = -intPart; fracScaled = -fracScaled; }
return new int[] { intPart, (int)fracScaled };
}
// 網路位元組序 (Big Endian) 讀取 4 bytes 組裝 int
byte[] bb = ...; // 來自 Socket/HTTP
int bits = ((bb[0]&0xFF)<<24) | ((bb[1]&0xFF)<<16) | ((bb[2]&0xFF)<<8) | (bb[3]&0xFF);
int[] result = intBitsToFloat(bits, 0); // 3 位小數
System.out.println("Value = " + result[0] + "." + String.format("%03d", Math.abs(result[1])));
以 Q16.16 格式 (高 16 位整數、低 16 位小數) 為例:
public final class Fixed16 {
public static final int ONE = 1 << 16; // 65536
public static final int MASK = 0xFFFF;
// 整數 → 定點數
public static int toFixed(int i) { return i << 16; }
public static int toFixed(float f) { return (int)(f * ONE); } // 僅編譯期/預處理用
// 定點數 → 整數 (截斷/四捨五入)
public static int toInt(int f) { return f >> 16; }
public static int toIntRound(int f) { return (f + 0x8000) >> 16; }
// 加減:直接整數加減
public static int add(int a, int b) { return a + b; }
public static int sub(int a, int b) { return a - b; }
// 乘法:(a*b) >> 16,防溢位用 long
public static int mul(int a, int b) {
return (int)(((long)a * b) >> 16);
}
// 除法:(a<<16) / b
public static int div(int a, int b) {
return (int)(((long)a << 16) / b);
}
// 三角函數查表 (0~360 度,精度 1 度)
private static final int[] SIN_TABLE = new int[361];
private static final int[] COS_TABLE = new int[361];
static {
for (int i = 0; i <= 360; i++) {
double rad = Math.toRadians(i);
SIN_TABLE[i] = (int)(Math.sin(rad) * ONE);
COS_TABLE[i] = (int)(Math.cos(rad) * ONE);
}
}
public static int sin(int deg) { return SIN_TABLE[deg % 360]; }
public static int cos(int deg) { return COS_TABLE[deg % 360]; }
// 平方根 (牛頓法)
public static int sqrt(int x) {
if (x <= 0) return 0;
int r = x >> 1; // 初猜
for (int i = 0; i < 5; i++) // 5 次迭代足夠
r = (r + div(x, r)) >> 1;
return r;
}
}
| 操作 | 定點數 | 軟浮點 | CLDC 1.1 原生 float |
|---|---|---|---|
| 加減 | 1~2 週期 | ~50 週期 | 1 週期 |
| 乘除 | ~10 週期 (long) | ~100 週期 | 2~5 週期 |
| 三角/開根 | 查表/5次迭代 | 極慢 (轉 float 再算) | 硬體/庫優化 |
| 精度 | 固定 1/65536 (~1.5e-5) | IEEE 754 單精度 (~7 位有效數字) | 同左 |
intBitsToFloat 單次轉換即可,不影響主迴圈CLDC 1.0 無 float 非絕對障礙。**定點數** 以極低開銷解決 90% 遊戲數學需求;**IEEE 754 軟解析** 處理外部浮點數據交互。現代 J2ME 開發應優先鎖定 CLDC 1.1 設備,獲得原生浮點支援,簡化代碼複雜度。