首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME 無浮點環境下的三角函數查表法實現:定點數 Sin/Cos 表生成與插值

     編輯:J2ME

背景:CLDC 1.0 無 float、無 Math.sin/cos

早期功能機僅支援整數運算。若需實現旋轉、軌跡、波形等遊戲邏輯,**查表法**是唯一可行方案:預計算 sin/cos 值存入陣列,運行時直接索引或線性插值。

WTK 官方 Demo 核心代碼解析


// 角度單位:度/10(0~36 對應 0~360°)
// 數值縮放:×256(8.8 定點數,即 1.0 = 256)
private static final int[] SINES = {
    0,    44,   88,  128,  165,  196,  222,  241,  252,  256,  // 0°~90°
    // 實際項目需擴展至 36 個條目(每 10° 一個)
};

// 正弦查詢:返回 sin(angle) * 256
private static int sineTimes256(int angle) {
    angle %= 36;                 // 歸一化 0~35
    if (angle < 0) angle += 36;  // 處理負角度

    if (angle <= 9) {                    // 0°~90°
        return SINES[angle];
    } else if (angle <= 18) {            // 90°~180°
        return SINES[18 - angle];
    } else if (angle <= 27) {            // 180°~270°
        return -SINES[angle - 18];
    } else {                             // 270°~360°
        return -SINES[36 - angle];
    }
}

// 餘弦 = 正弦相位偏移 90°(即 +9 步)
private static int cosineTimes256(int angle) {
    return sineTimes256(angle + 9);
}

進階:高精度表生成工具


// 離線生成 360 條目(1° 步長)×256 定點數表
public class SinTableGen {
    public static void main(String[] args) {
        int[] table = new int[360];
        for (int i = 0; i < 360; i++) {
            double rad = Math.toRadians(i);
            table[i] = (int) Math.round(Math.sin(rad) * 256);
        }
        // 輸出 Java 陣列初始化代碼
        System.out.print("private static final int[] SIN_TABLE = {");
        for (int i = 0; i < 360; i++) {
            if (i % 12 == 0) System.out.print("\n    ");
            System.out.print(table[i] + (i < 359 ? ", " : " };\n"));
        }
    }
}

線性插值提升精度

若步長 1° 仍不夠(如慢速旋轉),可做**定點數線性插值**:


// angle 為 0~3599(百分一度),返回 sin*256
public static int sin100(int angle) {
    angle %= 36000;
    if (angle < 0) angle += 36000;
    int idx = angle / 100;       // 整度索引
    int frac = angle % 100;      // 小數部分 0~99
    int v1 = SIN_TABLE[idx];
    int v2 = SIN_TABLE[(idx + 1) % 360];
    // 定點數插值:v1 + (v2-v1)*frac/100
    return v1 + ((v2 - v1) * frac) / 100;
}

定點數運算規則速查

運算公式(Q8.8 格式,縮放 256)範例
加/減直接加減a + b
乘法(a * b) >> 8(sin * amplitude) >> 8
除法(a << 8) / b(x << 8) / cos
轉浮點val / 256.0僅調試用

實戰應用:旋轉向量


// 向量 (x, y) 繞原點旋轉 angle 度(angle 為 0~359)
// 定點數版本,輸入輸出均為 ×256
public static void rotate256(int[] vec, int angle) {
    int sin = sineTimes256(angle);
    int cos = cosineTimes256(angle);
    int x = vec[0], y = vec[1];
    // x' = x*cos - y*sin
    // y' = x*sin + y*cos
    vec[0] = ((x * cos - y * sin) >> 8);
    vec[1] = ((x * sin + y * cos) >> 8);
}

記憶體 vs 精度權衡

方案表大小最大誤差適用場景
10° 步長 + 無插值36 × 2B = 72B~1.5%極度受限設備、粗略動畫
1° 步長 + 無插值360 × 2B = 720B~0.15%大多數遊戲足夠
0.1° 步長 + 線性插值3600 × 2B = 7.2KB< 0.001%高精度物理/軌跡
CORDIC 算法0B(純計算)可控無表空間、CPU 允許 10-20 迭代

結語

查表法是 J2ME 時代**解決無浮點三角函數的標準解法**。關鍵在於:選對步長與定點數格式、善用對稱性減半存儲、乘除遵循定點數移位規則。現代項目若維護舊代碼,可直接沿用;新項目建議要求 CLDC 1.1+ 直接用 Math.sin(硬體/軟浮點均可)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved