Penyelesaian masalah ketepatan pengiraan numerik dalam reka bentuk strategi JavaScript

Penulis:Kebaikan, Dicipta: 2020-07-09 11:31:01, Dikemas kini: 2023-10-28 15:32:47

img

Apabila menulis strategi JavaScript, kerana beberapa masalah bahasa skrip itu sendiri, ia sering membawa kepada masalah ketepatan numerik dalam pengiraan. Ia mempunyai pengaruh tertentu pada beberapa pengiraan dan penghakiman logik dalam program. Sebagai contoh, ketika mengira1 - 0.8atau0.33 * 1.1, data ralat akan dikira:

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

img

Jadi bagaimana untuk menyelesaikan masalah seperti itu?

Kemajuan maksimum nilai koma terapung adalah 17 tempat perpuluhan, tetapi ketepatan jauh lebih buruk daripada bilangan bulat semasa melakukan operasi; bilangan bulat ditukar kepada bilangan perpuluhan semasa melakukan operasi; dan ketika mengira operasi perpuluhan dalam Java dan JavaScript, kedua-duanya Pertama menukar bilangan perpuluhan kepada binari yang sepadan, sebahagian daripada bilangan perpuluhan tidak dapat ditukar sepenuhnya kepada binari, inilah kesilapan pertama. Selepas bilangan perpuluhan ditukar kepada binari, maka operasi antara binari dilakukan untuk mendapatkan hasil binari. Kemudian menukar hasil binari kepada desimal, di mana kesilapan kedua biasanya berlaku.

Untuk menyelesaikan masalah ini, saya mencari beberapa penyelesaian di Internet, dan menguji dan menggunakan penyelesaian berikut untuk menyelesaikan masalah ini:

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

Prinsipnya adalah untuk menukar dua operand yang akan dikira menjadi bilangan bulat untuk dikira untuk mengelakkan masalah ketepatan.

Dengan cara ini, apabila kita mahu program untuk meletakkan pesanan apabila harga pasaran ditambah dengan ketepatan harga minimum, kita tidak perlu risau tentang ketepatan berangka

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]) 
}

Pedagang yang berminat boleh membaca kod, memahami proses pengiraan, dialu-alukan untuk mengajukan soalan, belajar bersama dan maju bersama.


Berkaitan

Lebih lanjut