2019
টি এল; ডিআর
নীচে আমার ফাংশনটি ব্যবহার করুন if(cmpFloats($a, '==', $b)) { ... }
- পড়তে / লিখতে / পরিবর্তন করা সহজ:
cmpFloats($a, '<=', $b)
বনামbccomp($a, $b) <= -1
- কোন নির্ভরতা প্রয়োজন।
- যে কোনও পিএইচপি সংস্করণ দিয়ে কাজ করে।
- নেতিবাচক সংখ্যা নিয়ে কাজ করে।
- আপনি কল্পনা করতে পারেন দীর্ঘতম দশমিক নিয়ে কাজ করে।
- ডাউনসাইড: বিসিপি কম্পিউটারের চেয়ে সামান্য ধীর ()
সারসংক্ষেপ
আমি রহস্য উন্মোচন করব।
$a = 0.17;
$b = 1 - 0.83;// 0.17 (output)
// but actual value internally is: 0.17000000000000003996802888650563545525074005126953125
if($a == $b) {
echo 'same';
} else {
echo 'different';
}
// Output: different
সুতরাং আপনি নীচে চেষ্টা করে থাকলে, এটি সমান হবে:
if($b == 0.17000000000000003) {
echo 'same';
} else {
echo 'different';
}
// Output "same"
কিভাবে ভাসা আসল মান পেতে?
$b = 1 - 0.83;
echo $b;// 0.17
echo number_format($a, 100);// 0.1700000000000000399680288865056354552507400512695312500000000000000000000000000000000000000000000000
আপনি কিভাবে তুলনা করতে পারেন?
- বিসি ম্যাথ ফাংশন ব্যবহার করুন । (আপনি এখনও ডাব্লুটিএফ-আহা-গ্যাচা মুহুর্তগুলি পাবেন)
- আপনি PHP_FLOAT_EPSILON (পিএইচপি 7.2) ব্যবহার করে @ গ্ল্যাডন এর উত্তর চেষ্টা করতে পারেন।
- যদি এর সাথে ভাসমান তুলনা করা হয়
==
এবং !=
আপনি সেগুলি স্ট্রিংয়ে টাইপকাস্ট করতে পারেন তবে এটি পুরোপুরি কাজ করা উচিত:
স্ট্রিং সহ কাস্ট টাইপ করুন :
$b = 1 - 0.83;
if((string)$b === (string)0.17) {
echo 'if';
} else {
echo 'else';
}
// it will output "if"
বা এর সাথে টাইপকাস্ট number_format()
:
$b = 1 - 0.83;
if(number_format($b, 3) === number_format(0.17, 3)) {
echo 'if';
} else {
echo 'else';
}
// it will output "if"
সতর্কতা:
গাণিতিকভাবে ভাসমান (গুণমান, বিভাজন ইত্যাদির) সাথে তুলনা করে এমন সমাধানগুলি এড়ান যা বেশিরভাগ ক্ষেত্রে তারা কিছু সমস্যা সমাধান করবে এবং অন্যান্য সমস্যাগুলি প্রবর্তন করবে।
প্রস্তাবিত সমাধান
আমি খাঁটি পিএইচপি ফাংশন তৈরি করেছি (কোনও অবক্ষয় / গ্রন্থাগার / এক্সটেনশনের প্রয়োজন নেই)। প্রতিটি অঙ্ককে স্ট্রিং হিসাবে পরীক্ষা করে এবং তুলনা করে। নেতিবাচক সংখ্যা নিয়েও কাজ করে।
/**
* Compare numbers (floats, int, string), this function will compare them safely
* @param Float|Int|String $a (required) Left operand
* @param String $operation (required) Operator, which can be: "==", "!=", ">", ">=", "<" or "<="
* @param Float|Int|String $b (required) Right operand
* @param Int $decimals (optional) Number of decimals to compare
* @return boolean Return true if operation against operands is matching, otherwise return false
* @throws Exception Throws exception error if passed invalid operator or decimal
*/
function cmpFloats($a, $operation, $b, $decimals = 15) {
if($decimals < 0) {
throw new Exception('Invalid $decimals ' . $decimals . '.');
}
if(!in_array($operation, ['==', '!=', '>', '>=', '<', '<='])) {
throw new Exception('Invalid $operation ' . $operation . '.');
}
$aInt = (int)$a;
$bInt = (int)$b;
$aIntLen = strlen((string)$aInt);
$bIntLen = strlen((string)$bInt);
// We'll not used number_format because it inaccurate with very long numbers, instead will use str_pad and manipulate it as string
$aStr = (string)$a;//number_format($a, $decimals, '.', '');
$bStr = (string)$b;//number_format($b, $decimals, '.', '');
// If passed null, empty or false, then it will be empty string. So change it to 0
if($aStr === '') {
$aStr = '0';
}
if($bStr === '') {
$bStr = '0';
}
if(strpos($aStr, '.') === false) {
$aStr .= '.';
}
if(strpos($bStr, '.') === false) {
$bStr .= '.';
}
$aIsNegative = strpos($aStr, '-') !== false;
$bIsNegative = strpos($bStr, '-') !== false;
// Append 0s to the right
$aStr = str_pad($aStr, ($aIsNegative ? 1 : 0) + $aIntLen + 1 + $decimals, '0', STR_PAD_RIGHT);
$bStr = str_pad($bStr, ($bIsNegative ? 1 : 0) + $bIntLen + 1 + $decimals, '0', STR_PAD_RIGHT);
// If $decimals are less than the existing float, truncate
$aStr = substr($aStr, 0, ($aIsNegative ? 1 : 0) + $aIntLen + 1 + $decimals);
$bStr = substr($bStr, 0, ($bIsNegative ? 1 : 0) + $bIntLen + 1 + $decimals);
$aDotPos = strpos($aStr, '.');
$bDotPos = strpos($bStr, '.');
// Get just the decimal without the int
$aDecStr = substr($aStr, $aDotPos + 1, $decimals);
$bDecStr = substr($bStr, $bDotPos + 1, $decimals);
$aDecLen = strlen($aDecStr);
//$bDecLen = strlen($bDecStr);
// To match 0.* against -0.*
$isBothZeroInts = $aInt == 0 && $bInt == 0;
if($operation === '==') {
return $aStr === $bStr ||
$isBothZeroInts && $aDecStr === $bDecStr;
} else if($operation === '!=') {
return $aStr !== $bStr ||
$isBothZeroInts && $aDecStr !== $bDecStr;
} else if($operation === '>') {
if($aInt > $bInt) {
return true;
} else if($aInt < $bInt) {
return false;
} else {// Ints equal, check decimals
if($aDecStr === $bDecStr) {
return false;
} else {
for($i = 0; $i < $aDecLen; ++$i) {
$aD = (int)$aDecStr[$i];
$bD = (int)$bDecStr[$i];
if($aD > $bD) {
return true;
} else if($aD < $bD) {
return false;
}
}
}
}
} else if($operation === '>=') {
if($aInt > $bInt ||
$aStr === $bStr ||
$isBothZeroInts && $aDecStr === $bDecStr) {
return true;
} else if($aInt < $bInt) {
return false;
} else {// Ints equal, check decimals
if($aDecStr === $bDecStr) {// Decimals also equal
return true;
} else {
for($i = 0; $i < $aDecLen; ++$i) {
$aD = (int)$aDecStr[$i];
$bD = (int)$bDecStr[$i];
if($aD > $bD) {
return true;
} else if($aD < $bD) {
return false;
}
}
}
}
} else if($operation === '<') {
if($aInt < $bInt) {
return true;
} else if($aInt > $bInt) {
return false;
} else {// Ints equal, check decimals
if($aDecStr === $bDecStr) {
return false;
} else {
for($i = 0; $i < $aDecLen; ++$i) {
$aD = (int)$aDecStr[$i];
$bD = (int)$bDecStr[$i];
if($aD < $bD) {
return true;
} else if($aD > $bD) {
return false;
}
}
}
}
} else if($operation === '<=') {
if($aInt < $bInt ||
$aStr === $bStr ||
$isBothZeroInts && $aDecStr === $bDecStr) {
return true;
} else if($aInt > $bInt) {
return false;
} else {// Ints equal, check decimals
if($aDecStr === $bDecStr) {// Decimals also equal
return true;
} else {
for($i = 0; $i < $aDecLen; ++$i) {
$aD = (int)$aDecStr[$i];
$bD = (int)$bDecStr[$i];
if($aD < $bD) {
return true;
} else if($aD > $bD) {
return false;
}
}
}
}
}
}
$a = 1 - 0.83;// 0.17
$b = 0.17;
if($a == $b) {
echo 'same';
} else {
echo 'different';
}
// Output: different (wrong)
if(cmpFloats($a, '==', $b)) {
echo 'same';
} else {
echo 'different';
}
// Output: same (correct)
a and b are same
। এটি কি আপনার পুরো কোড?