자바스크립트 전략 설계에서 수치 계산 정확성 문제 해결

저자:선함, 2020-07-09 11:31:01에서 작성, 2023-10-28 15:32:47으로 업데이트

img

자바스크립트 전략을 작성할 때 스크립트 언어 자체의 문제로 인해 계산에 수학적 정확성 문제가 발생한다. 프로그램 내의 일부 계산과 논리적 판단에 어느 정도 영향을 미친다. 예를 들어 계산을 할 때1 - 0.8또는0.33 * 1.1, 오류 데이터는 계산됩니다:

function main() {
    var a = 1 - 0.8
    Log(a)
   
    var c = 0.33 * 1.1
    Log(c) 
}

img

그렇다면 이런 문제를 어떻게 해결할 수 있을까요?

부동 소수점 값의 최대 진전은 17 소수점이지만, 연산을 수행 할 때 정수는 정수보다 훨씬 나빠; 정수는 연산을 수행 할 때 소수점으로 변환됩니다; 그리고 자바와 자바스크립트에서 소수점을 계산할 때, 둘 다 먼저 소수점을 해당 바이너리로 변환하면 소수점의 일부가 완전히 바이너리로 변환 될 수 없습니다.

이 문제를 해결하기 위해, 저는 인터넷에서 몇 가지 솔루션을 검색했고, 다음 솔루션을 테스트하고 사용했습니다.

function mathService() {
    // addition
    this.add = function(a, b) {
        var c, d, e;
        try {
            c = a.toString().split(".")[1].length;   // Get the decimal length of a
        } catch (f) {
            c = 0;
        }
        try {
            d = b.toString().split(".")[1].length;   // Get the decimal length of b
        } catch (f) {
            d = 0;
        }
        //Find e first, multiply both a and b by e to convert to integer addition, then divide by e to restore
        return e = Math.pow(10, Math.max(c, d)), (this.mul(a, e) + this.mul(b, e)) / e;
    }
    
    // multiplication
    this.mul = function(a, b) {       
        var c = 0,
            d = a.toString(),         // Convert to string 
            e = b.toString();         // ...
        try {
            c += d.split(".")[1].length;      // c Accumulate the fractional digit length of a
        } catch (f) {}
        try {
            c += e.split(".")[1].length;      // c Accumulate the length of decimal places of b
        } catch (f) {}
        // Convert to integer multiplication, then divide by 10^c, move decimal point, restore, use integer multiplication without losing accuracy
        return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
    }

    // Subtraction
    this.sub = function(a, b) {
        var c, d, e;
        try {
            c = a.toString().split(".")[1].length;  // Get the decimal length of a
        } catch (f) {
            c = 0;
        }
        try {
            d = b.toString().split(".")[1].length;  // Get the decimal length of b
        } catch (f) {
            d = 0;
        }
        // Same as addition
        return e = Math.pow(10, Math.max(c, d)), (this.mul(a, e) - this.mul(b, e)) / e;
    }

    // Division
    this.div = function(a, b) {
        var c, d, e = 0,
            f = 0;
        try {
            e = a.toString().split(".")[1].length;
        } catch (g) {}
        try {
            f = b.toString().split(".")[1].length;
        } catch (g) {}
        // Similarly, convert to integer, after operation, restore
        return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), this.mul(c / d, Math.pow(10, f - e));
    }
}

function main() {
    var obj = new mathService()
    
    var a = 1 - 0.8
    Log(a)
    
    var b = obj.sub(1, 0.8)
    Log(b)
    
    var c = 0.33 * 1.1
    Log(c)
    
    var d = obj.mul(0.33, 1.1)
    Log(d)
}

img

원리는 계산해야 할 두 연산자를 정수로 변환하여 정확성 문제를 피하기 위해 계산하는 것입니다. 계산 후 (전수로 변환 할 때 확대량에 따라), 정확한 결과를 얻기 위해 계산 결과가 복원됩니다.

이 방법으로, 우리가 프로그램을 시장 가격 더하기 최소 가격 정확도에 주문을 할 때, 우리는 수학적 정확성에 대해 걱정할 필요가 없습니다

function mathService() {
....    // Omitted
}

function main() {
    var obj = new mathService()
    var depth = exchange.GetDepth()
    exchange.Sell(obj.add(depth.Bids[0].Price, 0.0001), depth.Bids[0].Amount, "Buy 1 order:", depth.Bids[0]) 
}

관심있는 거래자는 코드를 읽고 계산 과정을 이해할 수 있습니다. 질문하고 함께 배우고 함께 발전 할 수 있습니다.


관련

더 많은