javascript - जावास्क्रिप्ट में फ़्लोटिंग पॉइंट नंबर परिशुद्धता से कैसे निपटें?




floating-point (20)

0.6 * 3 यह कमाल है!)) मेरे लिए यह ठीक काम करता है:

function dec( num )
{
    var p = 100;
    return Math.round( num * p ) / p;
}

बहुत ही सरल))

मेरे पास निम्नलिखित डमी टेस्ट स्क्रिप्ट है:

function test(){
    var x = 0.1 * 0.2;
    document.write(x);
}
test();

यह परिणाम 0.020000000000000004 प्रिंट करेगा जबकि इसे केवल 0.02 प्रिंट करना चाहिए (यदि आप अपने कैलकुलेटर का उपयोग करते हैं)। जहां तक ​​मुझे समझ में आया यह फ्लोटिंग पॉइंट गुणा सटीकता में त्रुटियों के कारण है।

क्या किसी के पास अच्छा समाधान है ताकि इस तरह के मामले में मुझे सही परिणाम 0.02 ? मुझे पता है कि toFixed या राउंडिंग जैसे toFixed एक और संभावना होगी, लेकिन मैं वास्तव में बिना किसी काटने और गोल करने के पूरे प्रिंट को देखना चाहता हूं। बस जानना चाहता था कि आप में से कोई एक अच्छा, सुरुचिपूर्ण समाधान है या नहीं।

बेशक, अन्यथा मैं कुछ 10 अंकों या उससे भी अधिक दौर में जाऊंगा।


Phpjs.org पर राउंड () फ़ंक्शन अच्छी तरह से काम करता है: http://phpjs.org/functions/round

num = .01 + .06;  // yields 0.0699999999999
rnum = round(num,12); // yields 0.07

आप बाइनरी फ्लोटिंग पॉइंट प्रकारों के साथ सटीक दशमलव अंशों का प्रतिनिधित्व नहीं कर सकते (जो कि ईसीएमएस्क्रिप्ट फ्लोटिंग पॉइंट मानों का प्रतिनिधित्व करने के लिए उपयोग करता है)। इसलिए जब तक आप मनमाने ढंग से सटीक अंकगणितीय प्रकार या दशमलव आधारित फ़्लोटिंग पॉइंट प्रकार का उपयोग नहीं करते हैं तब तक एक सुरुचिपूर्ण समाधान नहीं होता है। उदाहरण के लिए, कैलकुलेटर ऐप जो विंडोज़ के साथ जहाजों को अब इस समस्या को हल करने के लिए मनमाने ढंग से सटीक अंकगणित का उपयोग करता है


आप सही हैं, इसका कारण फ़्लोटिंग पॉइंट नंबरों की सीमित सटीकता है। अपने तर्कसंगत संख्याओं को दो पूर्णांक संख्याओं के विभाजन के रूप में स्टोर करें और अधिकांश स्थितियों में आप बिना किसी सटीक हानि के नंबरों को स्टोर करने में सक्षम होंगे। जब प्रिंटिंग की बात आती है, तो आप परिणाम को अंश के रूप में प्रदर्शित करना चाह सकते हैं। प्रस्तावित प्रस्ताव के साथ, यह मामूली हो जाता है।

बेशक यह अपरिमेय संख्याओं के साथ ज्यादा मदद नहीं करेगा। लेकिन आप कम से कम समस्या का कारण बनने के तरीके में अपनी गणना को अनुकूलित करना चाहेंगे (उदाहरण के लिए sqrt(3)^2) जैसी स्थितियों का पता लगाना sqrt(3)^2)


इससे बचने के लिए आपको फ़्लोटिंग पॉइंट्स के बजाय पूर्णांक मानों के साथ काम करना चाहिए। तो जब आप मूल्यों के साथ 2 पद सटीक कार्य करना चाहते हैं * 100, 3 पदों के लिए 1000 का उपयोग करें। जब आप विभाजक को अलग करने के लिए एक फॉर्मेटर का उपयोग करते हैं।

कई प्रणालियां इस तरह से दशमलव के साथ काम करना छोड़ देते हैं। यही वजह है कि कई प्रणालियां डॉलर / यूरो (फ्लोटिंग पॉइंट के रूप में) के बजाय सेंट (पूर्णांक के रूप में) के साथ काम करती हैं।


उपयोग

var x = 0.1*0.2;
 x =Math.round(x*Math.pow(10,2))/Math.pow(10,2);

गणितीय रूप से इच्छुक: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

अनुशंसित दृष्टिकोण सुधार कारकों का उपयोग करना है (10 की उपयुक्त शक्ति से गुणा करें ताकि अंकगणित पूर्णांक के बीच होता है)। उदाहरण के लिए, 0.1 * 0.2 के मामले में, सुधार कारक 10 , और आप गणना कर रहे हैं:

> var x = 0.1
> var y = 0.2
> var cf = 10
> x * y
0.020000000000000004
> (x * cf) * (y * cf) / (cf * cf)
0.02

ए (बहुत तेज़) समाधान कुछ ऐसा दिखता है:

var _cf = (function() {
  function _shift(x) {
    var parts = x.toString().split('.');
    return (parts.length < 2) ? 1 : Math.pow(10, parts[1].length);
  }
  return function() { 
    return Array.prototype.reduce.call(arguments, function (prev, next) { return prev === undefined || next === undefined ? undefined : Math.max(prev, _shift (next)); }, -Infinity);
  };
})();

Math.a = function () {
  var f = _cf.apply(null, arguments); if(f === undefined) return undefined;
  function cb(x, y, i, o) { return x + f * y; }
  return Array.prototype.reduce.call(arguments, cb, 0) / f;
};

Math.s = function (l,r) { var f = _cf(l,r); return (l * f - r * f) / f; };

Math.m = function () {
  var f = _cf.apply(null, arguments);
  function cb(x, y, i, o) { return (x*f) * (y*f) / (f * f); }
  return Array.prototype.reduce.call(arguments, cb, 1);
};

Math.d = function (l,r) { var f = _cf(l,r); return (l * f) / (r * f); };

इस मामले में:

> Math.m(0.1, 0.2)
0.02

मैं निश्चित रूप से SinfulJS जैसे परीक्षण लाइब्रेरी का उपयोग करने की सलाह देता SinfulJS


दो फ्लोट वैल्यू जोड़ते समय यह कभी भी सटीक मान नहीं देता है इसलिए हमें इसे निश्चित संख्या में तय करने की आवश्यकता है जो हमें तुलना करने में मदद करेगी।

console.log ((parseFloat (0.1) + parseFloat (0.2))। tofixed (1) == parseFloat (0.3) .toFixed (1));

निम्नलिखित फ़ंक्शन का उपयोग करके आउटपुट:

var toFixedCurrency = function(num){
    var num = (num).toString();
    var one = new RegExp(/\.\d{1}$/).test(num);
    var two = new RegExp(/\.\d{2,}/).test(num);
    var result = null;

    if(one){ result = num.replace(/\.(\d{1})$/, '.$10');
    } else if(two){ result = num.replace(/\.(\d{2})\d*/, '.$1');
    } else { result = num*100; }

    return result;
}

function test(){
    var x = 0.1 * 0.2;
    document.write(toFixedCurrency(x));
}

test();

आउटपुट पर toFixedCurrency(x)


परिणाम जो आपको मिला है वह अलग-अलग भाषाओं, प्रोसेसर और ऑपरेटिंग सिस्टम में फ्लोटिंग पॉइंट कार्यान्वयन में सही और काफी सुसंगत है - फ्लोट वास्तव में एक डबल (या उच्चतर) होने पर परिवर्तन की एकमात्र चीज गलत होती है।

बाइनरी फ्लोटिंग पॉइंट्स में 0.1 दशमलव में 1/3 की तरह है (यानी 0.3333333333333 ... हमेशा के लिए), इसे संभालने का कोई सटीक तरीका नहीं है।

यदि आप फ्लोट्स से निपट रहे हैं तो हमेशा छोटी गोलियों की त्रुटियों की अपेक्षा करें, इसलिए आपको हमेशा प्रदर्शित परिणाम को कुछ समझदार तरीके से गोल करना होगा। बदले में आप बहुत तेज़ और शक्तिशाली अंकगणित हो जाते हैं क्योंकि सभी गणना प्रोसेसर की मूल बाइनरी में होती है।

अधिकांश समय समाधान समाधान-बिंदु अंकगणित पर स्विच नहीं करना है, मुख्य रूप से क्योंकि यह बहुत धीमा है और 99% उस समय आपको सटीकता की आवश्यकता नहीं है। यदि आप उन सामानों से निपट रहे हैं जिन्हें सटीकता के स्तर की आवश्यकता होती है (उदाहरण के लिए वित्तीय लेनदेन) जावास्क्रिप्ट शायद किसी भी तरह का उपयोग करने का सबसे अच्छा साधन नहीं है (जैसा कि आप निश्चित बिंदु प्रकार को लागू करना चाहते हैं, एक स्थिर भाषा शायद बेहतर है )।

आप सुरुचिपूर्ण समाधान की तलाश में हैं तो मुझे डर है कि यह है: फ्लोट्स जल्दी होते हैं लेकिन छोटी गोलियां होती हैं - हमेशा अपने परिणामों को प्रदर्शित करते समय समझदार कुछ के करीब होती हैं।


मुझे पेड्रो लाडरिया का समाधान पसंद है और कुछ इसी तरह का उपयोग करें।

function strip(number) {
    return (parseFloat(number).toPrecision(12));
}

पेड्रोस समाधान के विपरीत यह 0.9 99 तक बढ़ जाएगा ... दोहराना और कम से कम महत्वपूर्ण अंक पर प्लस / माइनस के लिए सटीक है।

नोट: 32 या 64 बिट फ्लोट्स से निपटने पर, आपको सर्वोत्तम परिणामों के लिए प्रेसिजन (7) और टू प्रेसिजन (15) का उपयोग करना चाहिए। इस प्रश्न को जानकारी के लिए क्यों देखें।


मुझे लगता है कि BigNumber.js मेरी आवश्यकताओं को पूरा करता है।

मनमानी-परिशुद्धता दशमलव और गैर-दशमलव अंकगणितीय के लिए एक जावास्क्रिप्ट लाइब्रेरी।

इसमें अच्छा documentation और लेखक प्रतिक्रिया के प्रति बहुत मेहनती प्रतिक्रिया दे रहा है।

एक ही लेखक के पास 2 अन्य समान पुस्तकालय हैं:

Big.js

मनमानी-परिशुद्धता दशमलव अंकगणितीय के लिए एक छोटी, तेज़ जावास्क्रिप्ट लाइब्रेरी। Bignumber.js करने के लिए छोटी बहन।

और Decimal.js

जावास्क्रिप्ट के लिए एक मनमाना-परिशुद्धता दशमलव प्रकार।

BigNumber का उपयोग करके कुछ कोड यहां दिया गया है:

$(function(){

  
  var product = BigNumber(.1).times(.2);  
  $('#product').text(product);

  var sum = BigNumber(.1).plus(.2);  
  $('#sum').text(sum);


});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<!-- 1.4.1 is not the current version, but works for this example. -->
<script src="http://cdn.bootcss.com/bignumber.js/1.4.1/bignumber.min.js"></script>

.1 &times; .2 = <span id="product"></span><br>
.1 &plus; .2 = <span id="sum"></span><br>


मैं प्रोग्रामिंग में इतना अच्छा नहीं हूं, लेकिन वास्तव में इस विषय में दिलचस्पी थी इसलिए मैंने यह समझने की कोशिश की कि किसी भी पुस्तकालय या स्क्रिप्ट का उपयोग किए बिना इसे कैसे हल किया जाए

मैंने इसे स्क्रैचपैड पर लिखा था

var toAlgebraic = function(f1, f2) {
    let f1_base = Math.pow(10, f1.split('.')[1].length);
    let f2_base = Math.pow(10, f2.split('.')[1].length);
    f1 = parseInt(f1.replace('.', ''));
    f2 = parseInt(f2.replace('.', ''));

    let dif, base;
    if (f1_base > f2_base) {
        dif = f1_base / f2_base;
        base = f1_base;
        f2 = f2 * dif;
    } else {
        dif = f2_base / f1_base;
        base = f2_base;
        f1 = f1 * dif;
    }

    return (f1 * f2) / base;
};

console.log(0.1 * 0.2);
console.log(toAlgebraic("0.1", "0.2"));

आपको इस कोड को दोबारा करने की आवश्यकता हो सकती है, क्योंकि मैं प्रोग्रामिंग में अच्छा नहीं हूं :)


यदि आप इस समस्या को छोटे ऑपरेशन के लिए बाईपास करना चाहते हैं तो आप parseFloat() और toFixed() उपयोग कर सकते हैं:

a = 0.1;
b = 0.2;

a + b = 0.30000000000000004;

c = parseFloat((a+b).toFixed(2));

c = 0.3;

a = 0.3;
b = 0.2;

a - b = 0.09999999999999998;

c = parseFloat((a-b).toFixed(2));

c = 0.1;

यह मेरे लिए काम करता है:

function round_up( value, precision ) { 
    var pow = Math.pow ( 10, precision ); 
    return ( Math.ceil ( pow * value ) + Math.ceil ( pow * value - Math.ceil ( pow * value ) ) ) / pow; 
}

round_up(341.536, 2); // 341.54

संख्या का उपयोग करें (1.234443) .toFixed (2); यह 1.23 प्रिंट करेगा

function test(){
    var x = 0.1 * 0.2;
    document.write(Number(x).toFixed(2));
}
test();

हैरानी की बात है कि, इस समारोह को अभी तक पोस्ट नहीं किया गया है, हालांकि अन्यों के समान बदलाव हैं। यह Math.round () के लिए एमडीएन वेब दस्तावेज़ों से है। यह संक्षेप में है और अलग-अलग परिशुद्धता के लिए अनुमति देता है।

function precisionRound(number, precision) {
  var factor = Math.pow(10, precision);
  return Math.round(number * factor) / factor;
}

console.log (सटीक राउंड (1234.5678, 1)); // अपेक्षित आउटपुट: 1234.6

console.log (सटीक राउंड (1234.5678, -1)); // अपेक्षित आउटपुट: 1230

var inp = document.querySelectorAll('input');
var btn = document.querySelector('button');

btn.onclick = function(){
  inp[2].value = precisionRound( parseFloat(inp[0].value) * parseFloat(inp[1].value) , 5 );
};

//MDN function
function precisionRound(number, precision) {
  var factor = Math.pow(10, precision);
  return Math.round(number * factor) / factor;
}
button{
display: block;
}
<input type='text' value='0.1'>
<input type='text' value='0.2'>
<button>Get Product</button>
<input type='text'>


फिक्स्ड-पॉइंट अंकगणित पर एक नज़र डालें। यह संभवतः आपकी समस्या का समाधान करेगा, यदि आप जिस नंबर पर काम करना चाहते हैं, वह छोटी है (उदाहरण के लिए, मुद्रा)। मैं इसे कुछ दशमलव मानों तक बंद कर दूंगा, जो सबसे सरल समाधान है।


मुसीबत

फ़्लोटिंग पॉइंट सभी दशमलव मानों को बिल्कुल स्टोर नहीं कर सकता है। तो फ़्लोटिंग पॉइंट प्रारूपों का उपयोग करते समय इनपुट मानों पर हमेशा गोल त्रुटियां होंगी। पाठ्यक्रम के इनपुट पर त्रुटियों के परिणामस्वरूप त्रुटियों पर त्रुटियां होती हैं। एक असतत कार्य या ऑपरेटर के मामले में उस बिंदु के आस-पास के आउटपुट पर बड़े अंतर हो सकते हैं जहां फ़ंक्शन या ऑपरेटर अलग है।

फ्लोटिंग पॉइंट मानों के लिए इनपुट और आउटपुट

तो, फ़्लोटिंग पॉइंट वेरिएबल्स का उपयोग करते समय, आपको हमेशा इसके बारे में पता होना चाहिए। और जो भी आउटपुट आप फ्लोटिंग पॉइंट्स के साथ गणना से चाहते हैं उसे हमेशा ध्यान में रखकर प्रारूपित / वातानुकूलित किया जाना चाहिए।
जब केवल निरंतर कार्य और ऑपरेटरों का उपयोग किया जाता है, वांछित परिशुद्धता के लिए गोल करने से अक्सर (कटौती न करें) करेंगे। फ़्लोट्स को स्ट्रिंग में कनवर्ट करने के लिए उपयोग की जाने वाली मानक स्वरूपण सुविधाएं आम तौर पर आपके लिए यह करती हैं।
चूंकि राउंडिंग एक त्रुटि जोड़ती है जो कुल त्रुटि को वांछित परिशुद्धता के आधा होने का कारण बन सकती है, आउटपुट को इनपुट की अपेक्षित सटीकता और आउटपुट की वांछित परिशुद्धता के आधार पर सही किया जाना चाहिए। तुम्हे करना चाहिए

  • अपेक्षित परिशुद्धता के लिए गोल इनपुट या सुनिश्चित करें कि उच्च परिशुद्धता के साथ कोई मूल्य दर्ज नहीं किया जा सकता है।
  • वांछित परिशुद्धता के 1/4 से कम या उसके बराबर है और इनपुट पर और गणना के दौरान त्रुटियों को गोल करने के कारण अधिकतम अपेक्षित त्रुटि से बड़ा होने से पहले आउटपुट में आउटपुट में एक छोटा सा मूल्य जोड़ें। यदि यह संभव नहीं है तो उपयोग की गई डेटा प्रकार की परिशुद्धता का संयोजन आपकी गणना के लिए वांछित आउटपुट परिशुद्धता प्रदान करने के लिए पर्याप्त नहीं है।

इन 2 चीजें आमतौर पर नहीं की जाती हैं और ज्यादातर मामलों में अधिकतर उपयोगकर्ताओं के लिए उन्हें मतभेदों के कारण मतभेद बहुत महत्वपूर्ण होते हैं, लेकिन मेरे पास पहले से ही एक प्रोजेक्ट था जहां उपयोगकर्ताओं द्वारा उन सुधारों के बिना आउटपुट स्वीकार नहीं किया गया था।

अलग-अलग फ़ंक्शन या ऑपरेटर (जैसे मॉड्यूल)

जब अलग ऑपरेटरों या कार्यों में शामिल होते हैं, तो यह सुनिश्चित करने के लिए आउटपुट की अपेक्षा की जा सकती है कि अतिरिक्त सुधार की आवश्यकता हो। गोल करने से पहले गोल करने और छोटे सुधार जोड़ने से समस्या हल नहीं हो सकती है।
इंटरमीडिएट गणना परिणामों पर एक विशेष चेक / सुधार, असतत फ़ंक्शन या ऑपरेटर को लागू करने के तुरंत बाद आवश्यक हो सकता है। एक विशिष्ट मामले (मॉड्यूल ऑपरेटर) के लिए, प्रश्न पर मेरा उत्तर देखें: मॉड्यूलस ऑपरेटर जावास्क्रिप्ट में आंशिक संख्या क्यों देता है?

समस्या होने से बेहतर बेहतर है

इस तरह की गणना के लिए डेटा प्रकारों (पूर्णांक या निश्चित बिंदु प्रारूप) का उपयोग करके इन समस्याओं से बचने के लिए अक्सर अधिक कुशल होता है जो त्रुटियों को गोल किए बिना अपेक्षित इनपुट स्टोर कर सकते हैं। इसका एक उदाहरण यह है कि आपको कभी भी वित्तीय गणनाओं के लिए फ़्लोटिंग पॉइंट मानों का उपयोग नहीं करना चाहिए।


    You can use library https://github.com/MikeMcl/decimal.js/. 
    it will   help  lot to give proper solution. 
    javascript console output 95 *722228.630 /100 = 686117.1984999999
    decimal library implementation 
    var firstNumber = new Decimal(95);
    var secondNumber = new Decimal(722228.630);
    var thirdNumber = new Decimal(100);
    var partialOutput = firstNumber.times(secondNumber);
    console.log(partialOutput);
    var output = new Decimal(partialOutput).div(thirdNumber);
    alert(output.valueOf());
    console.log(output.valueOf())== 686117.1985







floating-point