2019
टी एल; डॉ
इस तरह से नीचे मेरे फ़ंक्शन का उपयोग करें if(cmpFloats($a, '==', $b)) { ... }
- पढ़ने / लिखने / बदलने में आसान:
cmpFloats($a, '<=', $b)
बनामbccomp($a, $b) <= -1
- कोई निर्भरता की जरूरत है।
- किसी भी PHP संस्करण के साथ काम करता है।
- नकारात्मक संख्याओं के साथ काम करता है।
- सबसे लंबे दशमलव के साथ काम करता है जिसकी आप कल्पना कर सकते हैं।
- डाउनसाइड: बॉकम्पो की तुलना में थोड़ा धीमा ()
सारांश
मैं रहस्य का अनावरण करूंगा।
$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
आप तुलना कैसे कर सकते हैं?
- बीसी गणित कार्यों का उपयोग करें । (आप अभी भी बहुत सारे wtf-aha-gotcha क्षण प्राप्त करेंगे)
- PHP_FLOAT_EPSILON (PHP 7.2) का उपयोग करके आप @ Gladhon का उत्तर आज़मा सकते हैं।
- यदि तुलना तैरती है
==
और !=
, आप उन्हें तार के लिए टाइप कर सकते हैं, तो यह पूरी तरह से काम करना चाहिए:
स्ट्रिंग के साथ कास्ट टाइप करें :
$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"
चेतावनी:
ऐसे समाधानों से बचें जिनमें तैरने में हेरफेर करना गणितीय रूप से (गुणा करना, विभाजित करना, आदि) शामिल है, फिर तुलना करना, ज्यादातर वे कुछ समस्याओं को हल करेंगे और अन्य समस्याओं को पेश करेंगे।
सुझाया हुआ समाधान
मैंने शुद्ध PHP फ़ंक्शन (कोई भी डिपेंडेंसी / लाइब्रेरी / एक्सटेंशन की आवश्यकता नहीं) बनाई है। प्रत्येक अंक को स्ट्रिंग के रूप में जांचता है और तुलना करता है। नकारात्मक संख्याओं के साथ भी काम करता है।
/**
* 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
। क्या यह आपका पूरा कोड है?