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


617

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

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

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

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

बेशक, अन्यथा मैं कुछ 10 अंकों या इसके लिए गोल करूंगा।


118
दरअसल, त्रुटि इसलिए है क्योंकि 0.1एक परिमित बाइनरी फ्लोटिंग पॉइंट संख्या में मैप करने का कोई तरीका नहीं है ।
एरोन दिगुल्ला

10
अधिकांश अंशों को सटीक सटीकता के साथ दशमलव में नहीं बदला जा सकता है। एक अच्छी व्याख्या यहाँ है: docs.python.org/release/2.5.1/tut/node16.html
Nate Zaugg


53
@ सलमान: आपका जावास्क्रिप्ट रनटाइम इस समस्या को आपसे छुपाता है इसका मतलब यह नहीं है कि मैं गलत हूं।
एरोन दिगुल्ला

5
हारून से असहमत, बाइनरी में पूरी तरह से और पूरी तरह से 0.1 को कोड करने के तरीके हैं। लेकिन IEEE 754 यह आवश्यक रूप से परिभाषित नहीं करता है। एक प्रतिनिधित्व की कल्पना करें जहां आप एक तरफ बाइनरी में पूर्णांक भाग को कोड करेंगे, दूसरी ओर दशमलव भाग, एन दशमलव तक, बाइनरी में भी, सामान्य पूर्णांक की तरह> 0, और अंत में, दशमलव बिंदु की स्थिति । ठीक है, आप बिना किसी त्रुटि के 0.1 का प्रतिनिधित्व करेंगे। Btw, क्योंकि जेएस आंतरिक रूप से दशमलव की एक सीमित संख्या का उपयोग करता है, वे अंतिम दशमलव पर यह गलती नहीं करने के लिए हिम्मत जुटा सकते हैं।
फबिएन हदादी

जवाबों:


469

से फ्लोटिंग प्वाइंट गाइड :

मैं इस समस्या से बचने के लिए क्या कर सकता हूं?

यह इस बात पर निर्भर करता है कि आप किस प्रकार की गणनाएँ कर रहे हैं।

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

ध्यान दें कि पहला बिंदु केवल तभी लागू होता है जब आपको वास्तव में विशिष्ट सटीक दशमलव व्यवहार की आवश्यकता होती है। अधिकांश लोगों को इसकी आवश्यकता नहीं है, उन्हें बस चिढ़ है कि उनके कार्यक्रम 1/10 जैसी संख्याओं के साथ सही ढंग से काम नहीं करते हैं, बिना यह एहसास किए कि वे 1/3 के साथ भी नहीं हुए हैं।

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


11
मैंने BigDecimal के लिए आपके मृत लिंक पर ध्यान दिया और दर्पण की तलाश करते हुए, मुझे BigNumber नामक एक विकल्प मिला: jsfromhell.com/classes/bignumber
जैक्सनक्रा

4
@ बास-टी: हाँ, लेकिन फ़्लोट्स वास्तव में महत्व की लंबाई तक पूर्णांकों का प्रतिनिधित्व कर सकते हैं, और ईसीएमए मानक के अनुसार यह एक 64 बिट फ्लोट है। तो यह ठीक 2 से 52 तक पूर्णांक का प्रतिनिधित्व कर सकता है
माइकल बोर्गवर्ड

5
@ कार्ल: दशमलव १/१० को आधार २ में परिमित द्विआधारी अंश के रूप में नहीं दर्शाया जा सकता है, और यही जावास्क्रिप्ट संख्याएँ हैं। तो यह है कि वास्तव में एक ही समस्या वास्तव में।
माइकल बोरगवर्ड

12
मुझे आज पता चला कि जावास्क्रिप्ट में भी पूर्णांक में सटीक समस्याएं हैं। गौर कीजिए कि console.log(9332654729891549)वास्तव में प्रिंट 9332654729891548(यानी एक के बाद एक!)
मैलाथे

12
@mlathe: दोह .. ;P... के बीच 2⁵²= 4,503,599,627,370,496और 2⁵³= 9,007,199,254,740,992प्रतिनिधित्व योग्य संख्या पूर्णांक हैं । अगले सीमा के लिए, से 2⁵³करने के लिए 2⁵⁴, सब कुछ है से गुणा2 , तो प्रदर्शनीय नंबर दिए गए हैं उनको भी जिनके पास , आदि इसके विपरीत, पिछले श्रृंखला के लिए 2⁵¹करने के लिए 2⁵², अंतर है 0.5, आदि यह है की वजह से बस में वृद्धि | आधार कम हो | मूलांक 2 | द्विआधारी प्रतिपादक में 64-बिट फ्लोट मूल्य (जो बारी में की शायद ही कभी दस्तावेज 'अप्रत्याशित' व्यवहार बताते हैं की / toPrecision()के बीच मूल्यों के लिए 0और 1)।
गीतारलैब

125

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

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

पेड्रोस विलयन के विपरीत यह 0.999 राउंड ... दोहराएगा और कम से कम महत्वपूर्ण अंक पर प्लस / माइनस करने के लिए सटीक है।

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


21
किसी भी कारण से आपने 12 को चुना?
qwertymk

17
toPrecisionसंख्या के बजाय एक स्ट्रिंग लौटाता है। यह हमेशा वांछनीय नहीं हो सकता है।
SStanley

7
parseFloat (1.005) .toPreults (3) => 1.00
पीटर

5
@ user2428118, मुझे पता है, मैं गोलाई त्रुटि दिखाने के लिए था, इसका परिणाम 1.01 के बजाय 1.00 है
पीटर

9
@ User2428118 ने जो कहा वह पर्याप्त स्पष्ट नहीं हो सकता है: (9.99*5).toPrecision(2)= 49.95 के बजाय 50 क्योंकि खतना पूरी संख्या को गिनाता है, न कि केवल दशमलव। आप तब उपयोग कर सकते हैं , लेकिन यदि आपका परिणाम> 100 है, तो आप फिर से भाग्य से बाहर हैं, क्योंकि यह पहले तीन नंबर और एक दशमलव, इस तरह से डॉट को स्थानांतरित करने की अनुमति देगा, और इसे कम या अधिक अनुपयोगी बना देगा। मैंने इसके बजाय का उपयोग करना समाप्त कर दियाtoPrecision(4)toFixed(2)
एएक्सएल

79

गणितीय रूप से इच्छुक के लिए: 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 जैसे एक परीक्षण पुस्तकालय का उपयोग करने की सलाह देता हूं


1
इल को यह खूबसूरत वर्कअराउंड पसंद है लेकिन यह बिल्कुल सही नहीं लगता है: jsfiddle.net/Dm6F5/1 Math.a (76.65, 38.45) 115.10000000000002 रिटर्न
निकोलसियस

3
Math.m (10,2332226616) मुझे "-19627406800" दे रहा है, जो एक नकारात्मक मूल्य है ... मुझे आशा है कि एक ऊपरी सीमा होनी चाहिए - हो सकता है कि इस मुद्दे का कारण बन रहा हो। कृपया सुझाव दें
शिव कोमुरवेल्ली

1
यह सब बहुत अच्छा लग रहा है, लेकिन लगता है कि कहीं न कहीं एक गलती हुई है।
MrYellow

5
बहुत जल्दी समाधान उन्होंने कहा ... टूटा हुआ फिक्स कभी किसी ने नहीं कहा।
Cozzbie

2
उपरोक्त कोड का उपयोग न करें। यह पूरी तरह से एक 'त्वरित समाधान' नहीं है अगर यह काम नहीं करता है। यह गणित से संबंधित प्रश्न है, इसलिए सटीकता की आवश्यकता है।
डे्रनाई

49

क्या आप केवल गुणा कर रहे हैं? यदि ऐसा है तो आप अपने लाभ के लिए दशमलव अंकगणित के बारे में एक गुप्त रहस्य का उपयोग कर सकते हैं। वह वह है NumberOfDecimals(X) + NumberOfDecimals(Y) = ExpectedNumberOfDecimals। कहने का तात्पर्य यह है कि अगर हमारे पास है 0.123 * 0.12तो हम जानते हैं कि 5 दशमलव स्थान होंगे क्योंकि 0.1233 दशमलव स्थान हैं और 0.12दो हैं। इस प्रकार यदि जावास्क्रिप्ट ने हमें एक नंबर दिया जैसे 0.014760000002हम सटीक खोने के डर के बिना सुरक्षित रूप से 5 वें दशमलव स्थान पर गोल कर सकते हैं।


6
... और दशमलव स्थानों की सही मात्रा कैसे प्राप्त करें ।
लाइन-ओ

7
0.5 * 0.2 = 0.10; आप अभी भी 2 दशमलव स्थानों (या उससे कम) पर काट सकते हैं। लेकिन इस कानून से परे किसी गणितीय महत्व के साथ कोई संख्या कभी नहीं होगी।
नैट ज़ॉग्ग

3
क्या आपके पास इसके लिए एक प्रशस्ति पत्र है? यह भी ध्यान दें कि वही विभाजन के लिए सही नहीं है।
ग्रिफिन

3
@NateZaugg आप ओवरफ्लो करने वाले दशमलव को कम नहीं कर सकते हैं, आपको राशि को राउंड करना होगा, क्योंकि 2090.5 * 8.61 17999.205 है, लेकिन फ्लोट में यह 17999.2049999998 है
लॉस्टफील्ड्स

3
@Lostfields - आप सही हैं! मैंने अपना उत्तर अपडेट कर दिया है।
नैट ज़ॉग्ग

29

आप sprintfजावास्क्रिप्ट के लिए एक कार्यान्वयन की तलाश कर रहे हैं , ताकि आप उन में छोटी त्रुटियों के साथ फ्लोट लिख सकें (क्योंकि वे द्विआधारी प्रारूप में संग्रहीत हैं) एक प्रारूप में जो आप अपेक्षा करते हैं।

जावास्क्रिप्ट-स्प्रिंटफ की कोशिश करें , आप इसे इस तरह कहेंगे:

var yourString = sprintf("%.2f", yourNumber);

दो दशमलव स्थानों के साथ एक फ्लोट के रूप में अपना नंबर प्रिंट करने के लिए।

यदि आप प्रदर्शन के उद्देश्य से फ़्लोटिंग पॉइंट राउंडिंग के लिए अधिक फ़ाइलों को शामिल नहीं करते हैं, तो आप प्रदर्शन प्रयोजनों के लिए Number.toFixed () का भी उपयोग कर सकते हैं ।


4
मुझे लगता है कि यह सबसे साफ समाधान है। जब तक आपको वास्तव में परिणाम 0.02 होने की आवश्यकता है, तब तक छोटी त्रुटि नगण्य है। ऐसा लगता है कि क्या महत्वपूर्ण है कि आपका नंबर अच्छी तरह से प्रदर्शित हो , न कि आपके पास मनमाना परिशुद्धता हो।
लॉन्ग ऑयांग

2
प्रदर्शन के लिए यह वास्तव में सबसे अच्छा विकल्प है, जटिल गणनाओं के लिए, बोर्गवर्ड के उत्तर की जांच करें।
उपलब्ध नहीं है

4
लेकिन तब फिर से यह आपके स्ट्रिंग के समान ही लौटेगा जैसे कि आपकाNumber.toFixed (2)।
रॉबर्ट

27

मुझे BigNumber.js मिल रहा है जो मेरी जरूरतों को पूरा करता है।

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

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

एक ही लेखक के पास 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>


3
पुस्तकालय का उपयोग करना निश्चित रूप से मेरी राय में सबसे अच्छा विकल्प है।
एंथोनी

1
इस लिंक से github.com/MikeMcl/big.js/issues/45 bignumber.js -> वित्तीय दशमलव.जेएस -> वैज्ञानिक big.js -> ???
वी

20
var times = function (a, b) {
    return Math.round((a * b) * 100)/100;
};

--- या ---

var fpFix = function (n) {
    return Math.round(n * 100)/100;
};

fpFix(0.1*0.2); // -> 0.02

--- भी ---

var fpArithmetic = function (op, x, y) {
    var n = {
            '*': x * y,
            '-': x - y,
            '+': x + y,
            '/': x / y
        }[op];        

    return Math.round(n * 100)/100;
};

--- जैसे की ---

fpArithmetic('*', 0.1, 0.2);
// 0.02

fpArithmetic('+', 0.1, 0.2);
// 0.3

fpArithmetic('-', 0.1, 0.2);
// -0.1

fpArithmetic('/', 0.2, 0.1);
// 2

4
मुझे लगता है कि परिणामस्वरूप वही समस्या आएगी। आप एक अस्थायी बिंदु लौटाते हैं तो एक बड़ा मौका वापसी मूल्य भी "गलत" होगा।
गुर्टजन

1
बहुत चतुर और उपयोगी, +1।
जोनाटस वाकर

18

यह फ़ंक्शन दो फ़्लोटिंग पॉइंट संख्याओं के गुणन से आवश्यक सटीकता का निर्धारण करेगा और उचित परिशुद्धता के साथ परिणाम लौटाएगा। सुरुचिपूर्ण हालांकि यह नहीं है।

function multFloats(a,b){
  var atens = Math.pow(10,String(a).length - String(a).indexOf('.') - 1), 
      btens = Math.pow(10,String(b).length - String(b).indexOf('.') - 1); 
  return (a * atens) * (b * btens) / (atens * btens); 
}

Ew। हां, चल संख्या गणित के लिए संख्याओं को स्ट्रिंग में बदलें और उत्तर के रूप में प्रस्ताव भी दें।
एंड्रयू

16

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

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

कंसोल.लॉग (परिशुद्धता राउंड (1234.5678, 1)); // अपेक्षित आउटपुट: 1234.6

कंसोल.लॉग (परिशुद्धता राउंड (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'>

अद्यतन: अगस्त / 20/2019 बस इस त्रुटि को देखा। मेरा मानना ​​है कि यह Math.round () के साथ फ्लोटिंग पॉइंट प्रिसिजन एरर के कारण है।

precisionRound(1.005, 2) // produces 1, incorrect, should be 1.01

ये स्थितियाँ सही ढंग से काम करती हैं:

precisionRound(0.005, 2) // produces 0.01
precisionRound(1.0005, 3) // produces 1.001
precisionRound(1234.5, 0) // produces 1235
precisionRound(1234.5, -1) // produces 1230

ठीक कर:

function precisionRoundMod(number, precision) {
  var factor = Math.pow(10, precision);
  var n = precision < 0 ? number : 0.01 / factor + number;
  return Math.round( n * factor) / factor;
}

यह केवल दशमलव को दाईं ओर एक अंक जोड़ता है। MDN ने Math.round पेज अपडेट किया है ताकि शायद कोई बेहतर समाधान दे सके।


गलत जवाब। 10.2 हमेशा 10.19 पर लौटेगा। jsbin.com/tozogiwide/edit?html,js,console,output
Žilvinas

@ Postedilvinas आपके द्वारा पोस्ट किया गया JSBin लिंक ऊपर सूचीबद्ध MDN फ़ंक्शन का उपयोग नहीं करता है। मुझे लगता है कि आपकी टिप्पणी गलत व्यक्ति पर निर्देशित है।
हेलोवर्ल्डपीस

13

आपको बस अपना मन बनाना है कि आप वास्तव में कितने दशमलव अंक चाहते हैं - केक नहीं हो सकता है और इसे खा भी सकते हैं :-)

संख्यात्मक त्रुटियां हर आगे के संचालन के साथ जमा होती हैं और यदि आप इसे जल्दी नहीं काटते हैं तो यह सिर्फ बढ़ने वाला है। संख्यात्मक पुस्तकालयों जो परिणाम प्रस्तुत करते हैं जो हर चरण में अंतिम 2 अंकों को काटते हैं, संख्यात्मक सह-प्रोसेसर में भी "सामान्य" और "पूर्ण" समान कारण से लंबित होते हैं। Cuf-offs एक प्रोसेसर के लिए सस्ते होते हैं लेकिन एक स्क्रिप्ट में आपके लिए बहुत महंगे होते हैं (पोव (...) को गुणा और विभाजित और उपयोग करते हैं)। अच्छा गणित परिवाद आपके लिए कट-ऑफ करने के लिए मंजिल (x, n) प्रदान करेगा।

तो बहुत कम से कम आपको pov (10, n) के साथ वैश्विक संस्करण / स्थिरांक बनाना चाहिए - जिसका अर्थ है कि आपने जिस सटीकता की आवश्यकता पर निर्णय लिया है, वह :-) है:

Math.floor(x*PREC_LIM)/PREC_LIM  // floor - you are cutting off, not rounding

आप अंत में गणित और केवल कट-ऑफ भी रख सकते हैं - यह मानते हुए कि आप केवल परिणाम के साथ प्रदर्शन कर रहे हैं और नहीं कर रहे हैं। यदि आप ऐसा कर सकते हैं, तो .toFixed (...) अधिक कुशल हो सकता है।

यदि आप if-s / Comparison कर रहे हैं और तब कटौती नहीं करना चाहते हैं, तो आपको एक छोटे से स्थिरांक की भी आवश्यकता होती है, जिसे आमतौर पर eps कहा जाता है, जो अधिकतम अपेक्षित त्रुटि से एक दशमलव स्थान अधिक है। यह कहें कि आपका कट-ऑफ अंतिम दो दशमलव है - तब आपके eps में अंतिम (3rd सबसे महत्वपूर्ण) से 3 वें स्थान पर 1 है और आप इसका उपयोग यह तुलना करने के लिए कर सकते हैं कि परिणाम अपेक्षित eps सीमा के भीतर है (0.02 -eps <0.1) * 0.2 <0.02 + ईपीएस)।


किसी गरीब आदमी की गोलाई में आप 0.5 भी जोड़ सकते हैं: Math.floor (x * PREC_LIM + 0.5) / PREC_LIM
cmroanirgo

हालांकि, ध्यान दें कि उदाहरण के लिए Math.floor(-2.1)है -3। तो शायद उदाहरण के लिए जैसेMath[x<0?'ceil':'floor'](x*PREC_LIM)/PREC_LIM
22

floorइसके बजाय क्यों round?
क्विन कॉमेंडेंट

12

आप उपयोग कर सकते हैं 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;

11

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

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

2
@jrg कन्वेंशन द्वारा, "5" के साथ समाप्त होने वाली संख्याओं को निकटतम (यहां तक ​​कि हमेशा राउंडिंग या डाउन करने के लिए आपके परिणामों के लिए पूर्वाग्रह का परिचय दिया जाएगा) के साथ गोल किया जाता है। इसलिए, दो दशमलव स्थानों के लिए 4.725 राउंड वास्तव में 4.72 होना चाहिए।
मार्क ए। डरहम

9

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

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

बहुत सरल))


यह काम हालांकि कुछ के साथ होगा 8.22e-8 * 1.3?
पॉल कार्लटन

0.6 x 3 = 1.8, जिस कोड को आप परिणाम देते हैं वह 2 है ... इसलिए अच्छा नहीं है।
ज़ो

@Zyo इस उदाहरण में 1.8 देता है। आपने इसे कैसे चलाया?
Drenai

दिलचस्प। आप इसमें गुणा और भाग संचालकों को स्वैप कर सकते हैं और यह काम भी करता है।
एंड्रयू

9

ध्यान दें कि सामान्य प्रयोजन के उपयोग के लिए, यह व्यवहार स्वीकार्य होने की संभावना है।
समस्या तब उत्पन्न होती है जब एक उचित कार्रवाई निर्धारित करने के लिए उन फ़्लोटिंग पॉइंट मानों की तुलना की जाती है।
ES6 के आगमन के साथ, Number.EPSILONस्वीकार्य त्रुटि मार्जिन को निर्धारित करने के लिए एक नया स्थिरांक परिभाषित किया गया है:
इसलिए इस तरह तुलना करने के बजाय

0.1 + 0.2 === 0.3 // which returns false

आप इस तरह एक कस्टम तुलना फ़ंक्शन को परिभाषित कर सकते हैं:

function epsEqu(x, y) {
    return Math.abs(x - y) < Number.EPSILON;
}
console.log(epsEqu(0.1+0.2, 0.3)); // true

स्रोत: http://2ality.com/2015/04/numbers-math-es6.html#numberepsilon


मेरे मामले में नंबर .EPSILON बहुत छोटा था, जिसके परिणामस्वरूप जैसे0.9 !== 0.8999999761581421
टॉम

8

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

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

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

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

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


8

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

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


7

मुसीबत

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

फ्लोटिंग पॉइंट वैल्यू के लिए इनपुट और आउटपुट

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

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

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

असतत कार्य या ऑपरेटर (जैसे मोडुला)

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

बेहतर है कि समस्या होने से बचें

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


4

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


5
समस्या फ़्लोटिंग पॉइंट बनाम फिक्स्ड पॉइंट नहीं है, समस्या बाइनरी बनाम दशमलव है।
माइकल बोर्गवर्ड

4

मेरी चिल्लीडिक अरिथमेटिक लाइब्रेरी आजमाएँ, जिसे आप यहाँ देख सकते हैं । यदि आप एक बाद का संस्करण चाहते हैं, तो मैं आपको एक प्राप्त कर सकता हूं।


4

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


4

यहाँ छवि विवरण दर्ज करें

    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

3

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

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


आप ठीक कह रहे हैं, उस के लिए कारण चल बिन्दु संख्या की सीमित परिशुद्धता है - <pedant>वास्तव में, ओपी इसे नीचे अनिश्चित चल बिन्दु आपरेशनों के लिए रखा है, जो गलत है</pedant>
detly

3

मुझे मॉड 3 के साथ नॉटी राउंडिंग एरर की समस्या थी। कभी-कभी जब मुझे 0 मिलना चाहिए तो मुझे .000 ... 01। यह संभालना काफी आसान है, बस <= .01 के लिए परीक्षण करें। लेकिन फिर कभी-कभी मुझे 2.99999999999998 मिलता। ओह!

बिगनाइट्स ने समस्या को हल किया, लेकिन एक और विडंबना यह है कि कुछ विडंबनापूर्ण, समस्या। जब बिगनाइट्स में 8.5 लोड करने की कोशिश की जा रही थी, तो मुझे बताया गया कि यह वास्तव में 8.4999 था ... और इसमें 15 से अधिक महत्वपूर्ण अंक थे। इसका मतलब था कि बिगनेट्स इसे स्वीकार नहीं कर सकते (मेरा मानना ​​है कि मैंने इस समस्या का उल्लेख कुछ विडंबनापूर्ण है)।

विडंबना समस्या का सरल समाधान:

x = Math.round(x*100);
// I only need 2 decimal places, if i needed 3 I would use 1,000, etc.
x = x / 100;
xB = new BigNumber(x);

2

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

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

2

Javascript संकेतक में फ़्लोटिंग-पॉइंट हेरफेर समस्याओं से बचने के लिए दशमलव .js , big.js या bignumber.js का उपयोग किया जा सकता है

0.1 * 0.2                                // 0.020000000000000004
x = new Decimal(0.1)
y = x.times(0.2)                          // '0.2'
x.times(0.2).equals(0.2)                  // true

big.js: न्यूनतर; प्रयोग करने में आसान; दशमलव स्थानों में सटीक निर्दिष्ट; परिशुद्धता केवल विभाजन पर लागू होती है।

bignumber.js: कुर्सियां ​​2-64; कॉन्फ़िगरेशन विकल्प; NaN; इन्फिनिटी; दशमलव स्थानों में सटीक निर्दिष्ट; परिशुद्धता केवल विभाजन पर लागू होती है; आधार उपसर्ग।

दशमलव.जेएस: कुर्सियां ​​2-64; कॉन्फ़िगरेशन विकल्प; NaN; इन्फिनिटी; गैर-पूर्णांक शक्तियाँ, ऍक्स्प, ln, लॉग; महत्वपूर्ण अंकों में निर्दिष्ट सटीकता; परिशुद्धता हमेशा लागू; यादृच्छिक संख्या।

विस्तृत तुलना के लिए लिंक


2

एलिगेंट, प्रेडिक्टेबल और रियूजेबल

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

// First extend the native Number object to handle precision. This populates
// the functionality to all math operations.

Object.defineProperty(Number.prototype, "decimal", {
  get: function decimal() {
    Number.precision = "precision" in Number ? Number.precision : 3;
    var f = Math.pow(10, Number.precision);
    return Math.round( this * f ) / f;
  }
});


// Now lets see how it works by adjusting our global precision level and 
// checking our results.

console.log("'1/3 + 1/3 + 1/3 = 1' Right?");
console.log((0.3333 + 0.3333 + 0.3333).decimal == 1); // true

console.log(0.3333.decimal); // 0.333 - A raw 4 digit decimal, trimmed to 3...

Number.precision = 3;
console.log("Precision: 3");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0.1
console.log((0.008 + 0.002).decimal); // 0.01
console.log((0.0008 + 0.0002).decimal); // 0.001

Number.precision = 2;
console.log("Precision: 2");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0.1
console.log((0.008 + 0.002).decimal); // 0.01
console.log((0.0008 + 0.0002).decimal); // 0

Number.precision = 1;
console.log("Precision: 1");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0.1
console.log((0.008 + 0.002).decimal); // 0
console.log((0.0008 + 0.0002).decimal); // 0

Number.precision = 0;
console.log("Precision: 0");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0
console.log((0.008 + 0.002).decimal); // 0
console.log((0.0008 + 0.0002).decimal); // 0

चीयर्स!


2
यदि आप कम करना चुनते हैं, तो कम से कम एक कारण प्रदान करें।
बर्नस्टो

1

उपयोग

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

4
हम्म ... लेकिन ध्यान दें, यह हमेशा 2 दशमलव तक गोल होता है। यह निश्चित रूप से एक विकल्प होगा, लेकिन गणना 0.55 * 0.55 के बारे में क्या है (क्योंकि मुझे पहले से सटीक संख्या नहीं पता है। यह 0.3025 के बजाय 0.3 देगा। बेशक मैं तब उपयोग कर सकता हूं Math.round(x*Math.pow(10,4))/Math.pow(10,4);। गोलाई हमेशा एक विकल्प है। लेकिन मैं सिर्फ यह जानना चाहता था कि क्या कोई बेहतर उपाय है
जूरी-

10.2 हमेशा 10.19 रिटर्न jsbin.com/tozogiwide/edit?html,js,console,output
Zilvinas

1

सुरुचिपूर्ण नहीं है लेकिन काम करता है (ट्रेलिंग शून्य हटाता है)

var num = 0.1*0.2;
alert(parseFloat(num.toFixed(10))); // shows 0.02

6
toFixed हमेशा काम नहीं करता है: stackoverflow.com/questions/661562/…
सैम

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
दुर्भाग्य से, राउंड_अप (4.15,2) => 4.16।
j

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)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.