এই প্রশ্নটি জটিল।
ধরুন আমাদের একটি ফাংশন রয়েছে, roundTo2DP(num)
এটি একটি আর্গুমেন্ট হিসাবে ভাসিয়ে নেয় এবং 2 টি দশমিক জায়গায় গোল করে একটি মান দেয়। এই প্রতিটি প্রকাশের মূল্যায়ন করা উচিত কী?
roundTo2DP(0.014999999999999999)
roundTo2DP(0.0150000000000000001)
roundTo2DP(0.015)
'সুস্পষ্ট' উত্তরটি হ'ল প্রথম উদাহরণটি 0.01 এর সাথে গোল হওয়া উচিত (কারণ এটি 0.02 এর তুলনায় 0.01 এর কাছাকাছি) এবং অন্য দুটি 0.02 এর কাছাকাছি হওয়া উচিত (কারণ 0.015000000000000000001 0.01 থেকে 0.01 এর কাছাকাছি এবং কারণ 0.015 এর মাঝামাঝি মাঝখানে তাদের এবং একটি গাণিতিক সম্মেলন রয়েছে যে এই জাতীয় সংখ্যাগুলি গোল হয়ে যায়)।
আপনি যে ক্যাপটি অনুমান করতে পারেন, তা হ'ল roundTo2DP
সম্ভবত সেই স্পষ্ট উত্তরগুলি দেওয়ার জন্য বাস্তবায়ন করা যায় না , কারণ এতে পাস হওয়া তিনটি নম্বরই একই সংখ্যা । আইইইই 754 বাইনারি ফ্লোটিং পয়েন্ট সংখ্যা (জাভাস্ক্রিপ্ট দ্বারা ব্যবহৃত ধরণের) হুবহু বেশিরভাগ অ-পূর্ণসংখ্যার সংখ্যা উপস্থাপন করতে পারে না এবং সুতরাং উপরের তিনটি সংখ্যাসূচক অক্ষরটি একটি কাছের বৈধ ভাসমান পয়েন্ট সংখ্যাটিতে গোলাকার হয়ে যায়। এই সংখ্যাটি যেমন হয় তেমনি ঠিক ঠিক
0,01499999999999999944488848768742172978818416595458984375
যা 0.02 এর চেয়ে 0.01 এর কাছাকাছি।
আপনি দেখতে পাচ্ছেন যে আপনার ব্রাউজার কনসোল, নোড শেল, বা অন্য জাভাস্ক্রিপ্ট ইন্টারপ্রেটারে সমস্ত তিনটি সংখ্যা একই। কেবল তাদের তুলনা করুন:
> 0.014999999999999999 === 0.0150000000000000001
true
সুতরাং যখন আমি লিখি m = 0.0150000000000000001
, আমি যেটিরm
সাথে শেষ করি তার সঠিক মানটি তার 0.01
চেয়ে বেশি কাছাকাছি 0.02
। এবং এখনও, যদি আমি রূপান্তর করিm
একটি স্ট্রিংয়ে ...
> var m = 0.0150000000000000001;
> console.log(String(m));
0.015
> var m = 0.014999999999999999;
> console.log(String(m));
0.015
... আমি 0.015 পেয়েছি, যা 0.02 এর মধ্যে হওয়া উচিত, এবং যা লক্ষণীয় নয় 56-দশমিক স্থানের নম্বরটি আমি আগে বলেছি যে এই সংখ্যার সমস্তটি ঠিক সমান ছিল। তাহলে এটি কি অন্ধকার যাদু?
উত্তর নাম ECMAScript স্পেসিফিকেশন পাওয়া যেতে পারে, বিভাগে 7.1.12.1: ToString নম্বর টাইপ করুন প্রয়োগ । এখানে কিছু সংখ্যার মিটারকে একটি স্ট্রিংয়ে রূপান্তর করার নিয়ম স্থির করা হয়েছে। মূল অংশ বিন্দু 5, যা একটি পূর্ণসংখ্যা গুলি উৎপন্ন হয় যার সংখ্যা স্ট্রিং উপস্থাপনা ব্যবহার করা হবে মিটার :
দিন এন , ট , এবং গুলি পূর্ণসংখ্যার যেমন যে হতে ট ≥ 1, 10 ট -1 ≤ গুলি <10 ট জন্য নম্বর মান গুলি × 10 এন - ট হয় মি , এবং ট সম্ভব ছোট হয়। লক্ষ্য করুন k এর দশমিক প্রতিনিধিত্ব ডিজিটের সংখ্যা গুলি , যে গুলি 10 দ্বারা বিভাজ্য নয়, এবং যে অন্তত উল্লেখযোগ্য অঙ্ক গুলি অগত্যা স্বতন্ত্র এই শর্তগুলির সাথে কর্তৃক নির্ধারিত করা হয় না।
এখানে মূল অংশটি হ'ল প্রয়োজনীয় " কে যতটা সম্ভব ছোট"। কি যে প্রয়োজন পরিমাণ প্রয়োজন যে দেওয়া একটি সংখ্যা m
, মান String(m)
থাকা আবশ্যক ডিজিটের অন্তত সম্ভব সংখ্যা এখনও প্রয়োজন যে পরিতৃপ্ত Number(String(m)) === m
। যেহেতু আমরা এটি ইতিমধ্যে জানি0.015 === 0.0150000000000000001
, এটি এখন কেন স্পষ্ট String(0.0150000000000000001) === '0.015'
হবে তা সত্য।
অবশ্যই, এই আলোচনার কেউ সরাসরি উত্তর দেওয়া হয়েছে কি roundTo2DP(m)
করা উচিত ফিরে। যদি m
এর সঠিক মান 0.01499999999999999944488848768742172978818416595458984375 হয় তবে এর স্ট্রিং প্রতিনিধিত্ব '0.015' হয় তবে তার মানটি কী সঠিক উত্তরটি কী - গাণিতিকভাবে, ব্যবহারিকভাবে, দার্শনিকভাবে বা যাই হোক না কেন - যখন আমরা এটি দুটি দশমিক স্থানে গোল করি?
এর কোনও একক সঠিক উত্তর নেই। এটি আপনার ব্যবহারের ক্ষেত্রে নির্ভর করে। আপনি সম্ভবত স্ট্রিং প্রতিনিধিত্বকে সম্মান করতে এবং উপরের দিকে গোল করতে চান:
- প্রতিনিধিত্ব করা হচ্ছে মানটি অন্তর্নিহিত পৃথক, যেমন দিনারগুলির মতো 3-দশমিক স্থান মুদ্রায় পরিমাণ মুদ্রা। এই ক্ষেত্রে, সত্য 0.015 মত একটি সংখ্যা মান হয় 0.015 এবং 0,0149999999 ... উপস্থাপনা এটি বাইনারি ফ্লোটিং পয়েন্ট পায় একটি rounding ত্রুটি। (অবশ্যই, অনেক যুক্তিযুক্তভাবে যুক্তিযুক্ত হতে পারে যে, এই জাতীয় মানগুলি পরিচালনা করার জন্য আপনার দশমিক পাঠাগার ব্যবহার করা উচিত এবং এগুলি প্রথম স্থানে বাইনারি ভাসমান পয়েন্ট নম্বর হিসাবে উপস্থাপন করবেন না))
- মানটি কোনও ব্যবহারকারী টাইপ করেছিলেন। এক্ষেত্রে আবার, প্রবেশ করা ঠিক দশমিক সংখ্যাটি নিকটতম বাইনারি ভাসমান পয়েন্ট উপস্থাপনার চেয়ে বেশি 'সত্য'।
অন্যদিকে, আপনি সম্ভবত বাইনারি ভাসমান পয়েন্ট মানটিকে সম্মান করতে এবং নীচের দিকে গোল করতে চান যখন আপনার মান অন্তর্নিহিত ধারাবাহিক স্কেল থেকে থাকে - উদাহরণস্বরূপ, যদি এটি সেন্সর থেকে পড়া হয়।
এই দুটি পদ্ধতির জন্য আলাদা কোড দরকার। সংখ্যার স্ট্রিং প্রতিনিধিত্বকে সম্মান জানাতে, আমরা যখন স্কুলে আপনি যে একই অ্যালগরিদম ব্যবহার করেছিলেন আপনি স্কুলে ব্যবহৃত একই অ্যালগরিদমটি ব্যবহার করে, আমরা (নিজস্ব যুক্তিযুক্ত সূক্ষ্ম কোডের একটি বিট সহ) স্ট্রিং উপস্থাপনার উপর সরাসরি কাজ করে তা আমাদের নিজস্ব বৃত্তাকার প্রয়োগ করতে পারি can কিভাবে গোল করার সংখ্যা শেখানো হয়েছিল। নীচে একটি উদাহরণ যা দশমিক পয়েন্টের পরে পিছনে শূণ্যগুলি কেড়ে নিয়ে "কেবল তখনই প্রয়োজন হয়" সংখ্যাকে 2 দশমিক স্থানে প্রতিনিধিত্ব করার জন্য ওপি'র প্রয়োজনীয়তার সম্মান করে; আপনার অবশ্যই এটি আপনার যথাযথ প্রয়োজনগুলিতে সামঞ্জস্য করতে হবে।
/**
* Converts num to a decimal string (if it isn't one already) and then rounds it
* to at most dp decimal places.
*
* For explanation of why you'd want to perform rounding operations on a String
* rather than a Number, see http://stackoverflow.com/a/38676273/1709587
*
* @param {(number|string)} num
* @param {number} dp
* @return {string}
*/
function roundStringNumberWithoutTrailingZeroes (num, dp) {
if (arguments.length != 2) throw new Error("2 arguments required");
num = String(num);
if (num.indexOf('e+') != -1) {
// Can't round numbers this large because their string representation
// contains an exponent, like 9.99e+37
throw new Error("num too large");
}
if (num.indexOf('.') == -1) {
// Nothing to do
return num;
}
var parts = num.split('.'),
beforePoint = parts[0],
afterPoint = parts[1],
shouldRoundUp = afterPoint[dp] >= 5,
finalNumber;
afterPoint = afterPoint.slice(0, dp);
if (!shouldRoundUp) {
finalNumber = beforePoint + '.' + afterPoint;
} else if (/^9+$/.test(afterPoint)) {
// If we need to round up a number like 1.9999, increment the integer
// before the decimal point and discard the fractional part.
finalNumber = Number(beforePoint)+1;
} else {
// Starting from the last digit, increment digits until we find one
// that is not 9, then stop
var i = dp-1;
while (true) {
if (afterPoint[i] == '9') {
afterPoint = afterPoint.substr(0, i) +
'0' +
afterPoint.substr(i+1);
i--;
} else {
afterPoint = afterPoint.substr(0, i) +
(Number(afterPoint[i]) + 1) +
afterPoint.substr(i+1);
break;
}
}
finalNumber = beforePoint + '.' + afterPoint;
}
// Remove trailing zeroes from fractional part before returning
return finalNumber.replace(/0+$/, '')
}
ব্যবহারের উদাহরণ:
> roundStringNumberWithoutTrailingZeroes(1.6, 2)
'1.6'
> roundStringNumberWithoutTrailingZeroes(10000, 2)
'10000'
> roundStringNumberWithoutTrailingZeroes(0.015, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes('0.015000', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes(1, 1)
'1'
> roundStringNumberWithoutTrailingZeroes('0.015', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes(0.01499999999999999944488848768742172978818416595458984375, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes('0.01499999999999999944488848768742172978818416595458984375', 2)
'0.01'
উপরে ফাংশন সম্ভবত আপনি ব্যবহারকারীর সংখ্যাটি সাক্ষ্য দিতে এড়াতে ব্যবহার করতে চান যে তারা ভুলভাবে গোল হয়ে গেছে।
(বিকল্প হিসাবে, আপনি গোলাকার 10 গ্রন্থাগারটিও চেষ্টা করতে পারেন যা বুনোভাবে আলাদা বাস্তবায়নের সাথে অনুরূপ আচরণের ফাংশন সরবরাহ করে))
তবে আপনার যদি দ্বিতীয় ধরণের সংখ্যা থাকে - অবিচ্ছিন্ন স্কেল থেকে নেওয়া একটি মান, যেখানে কম দশমিক স্থানের সাথে আনুমানিক দশমিক উপস্থাপনা বেশি রয়েছে তাদের তুলনায় আরও নির্ভুল বলে মনে করার কোনও কারণ নেই ? সেক্ষেত্রে আমরা করি না স্ট্রিং উপস্থাপনা সম্মান চান কারণ যে উপস্থাপনা (বৈশিষ্ট ব্যাখ্যা হিসাবে) আগে থেকেই বাছাই করা অফ বৃত্তাকার; আমরা "0.014999999 ... 0.015 পর্যন্ত 375 রাউন্ড, যা 0.02 অবধি, তাই 0.014999999 ... 0.02 পর্যন্ত 0.05" পর্যন্ত ভুল বলতে চাই না।
এখানে আমরা কেবল অন্তর্নির্মিত toFixed
পদ্ধতিটি ব্যবহার করতে পারি । দ্রষ্টব্য যে Number()
স্ট্রিং দ্বারা ফিরে এসে কল করে toFixed
আমরা একটি নম্বর পাই যার স্ট্রিং প্রতিনিধির কোনও অনুবর্তনযোগ্য শূন্য নেই (জাভাস্ক্রিপ্ট যেভাবে কোনও সংখ্যার স্ট্রিং উপস্থাপনা গণনা করে, তার জন্য ধন্যবাদ, এই উত্তরে আগে আলোচনা করা হয়েছে)।
/**
* Takes a float and rounds it to at most dp decimal places. For example
*
* roundFloatNumberWithoutTrailingZeroes(1.2345, 3)
*
* returns 1.234
*
* Note that since this treats the value passed to it as a floating point
* number, it will have counterintuitive results in some cases. For instance,
*
* roundFloatNumberWithoutTrailingZeroes(0.015, 2)
*
* gives 0.01 where 0.02 might be expected. For an explanation of why, see
* http://stackoverflow.com/a/38676273/1709587. You may want to consider using the
* roundStringNumberWithoutTrailingZeroes function there instead.
*
* @param {number} num
* @param {number} dp
* @return {number}
*/
function roundFloatNumberWithoutTrailingZeroes (num, dp) {
var numToFixedDp = Number(num).toFixed(dp);
return Number(numToFixedDp);
}