convert scientific notation to decimal with php - php

math with bitcoin is giving me problems
$value = bcmul((float)$TotalMoney, $p,8);
$value = bcdiv((float)$Value, 100,8);
returns 8.431e-05 as one of the values in the script
i've tried
$newNum = (float)$value;
$newNum = number_format((float)$value, 8);
$newNum = sprintf('%.8f',$value);
function scientific_notation($in_float_value, $in_decimal_place_count = -1)
{
// Get the exponent
$abs_float_value = abs($in_float_value);
$exponent = floor($abs_float_value == 0 ? 0 : log10($abs_float_value));
// Scale to get the mantissa
$in_float_value *= pow(10, -$exponent);
// Create the format string based
// on the requested number of decimal places.
$format = ($in_decimal_place_count >= 0) ? "." . $in_decimal_place_count : "";
//echo("Format0: $format");
// Format the exponent part using zero padding.
$formatted_exponent = "+" . sprintf("%02d", $exponent);
if($exponent < 0.0)
{
$formatted_exponent = "-" . sprintf("%02d", -$exponent);
}
$format = "%" . $format . "fe%s";
//echo("Format1: $format");
// Return the final value combining mantissa and exponent
return sprintf($format, $in_float_value, $exponent);
}
$newNum = scientific_notation($value,8);
Tried it in phpfiddle and it works. maybe the problem is storing it in a db. It's stores as 8.431e-05 in the database
what am I doing wrong?

Use the exemple below to convert Scientific Notation to float/decimal on PHP:
echo sprintf('%f', floatval('-1.0E-5'));//default 6 decimal places
echo sprintf('%.8f', floatval('-1.0E-5'));//force 8 decimal places
echo rtrim(sprintf('%f',floatval(-1.0E-5)),'0');//remove trailing zeros

When working with Bitcoin balances it is recommended to store amounts in a database in satoshis as an integer and then you can convert it back to 8 decimals when displaying it on the screen to users.
$amount = 0.0132;
$convert = $amount * 100000000;
// store in DB as the converted amount 1320000 as an integer
// when grabbing from DB convert it back
$databaseValue = 1320000;
$convertBack = $databaseValue / 100000000;
$display = number_format($convertBack, 8);
echo $display;

Related

PHP Decimal128 string formating

I am using MongoDB to store values as Decimal128 and using PHP with Twig to display them. My question is there a format the output with a thousands separator? I have tried using number_format, but that doesn't work because the value is a string not a int or float. I don't want to type cast the value because I want the value to be precision.
Examples:
1000.382 = 1,000.382
99.01 = 99.01
1900000 = 1,900,000
I wrote a function to do this. Still wondering if there is a better way to do it.
<?php
$n = '12345.001';
echo fNumString($n);
function fNumString ($number_string) {
$ex_num = explode('.', $number_string);
$whole_num_len = strlen($ex_num[0]);
$formated = '';
if ($whole_num_len > 3) {
for ($i = 0; $i < $whole_num_len; $i++) {
$formated .= $ex_num[0][$i];
if ((($whole_num_len - ($i + 1)) % 3) == 0 && $whole_num_len != ($i + 1))
$formated .= ',';
}
} else
$formated = $ex_num[0];
if (count($ex_num) == 2)
$formated .= '.' . $ex_num[1];
return $formated;
}
You could:
split the number string into integer and decimal parts using explode,
reverse the integer part using strrev,
add a thousands separator every 3 digits within that integer part using preg_replace,
reverse the integer part back using strrev,
return it concatenated with the decimal separator and the decimal part
Code:
function fNumString(string $numberString, string $decimalPoint = '.', string $thousandsSeparator = ','): string
{
[$integerPart, $decimalPart] = array_pad(explode('.', $numberString, 2), 2, null);
$integerPart = strrev(preg_replace('/\d{3}(?=\d)/', '\0' . $thousandsSeparator, strrev($integerPart)));
return $integerPart . ($decimalPart ? $decimalPoint . $decimalPart : '');
}
Demo: https://3v4l.org/m3jUC
Note: you could leave out the last 2 parameters of number_format, I like keeping them out for clarity (and in case they change the default values later for some reason).

Round up decimal number for specific decimal places in PHP

I want to round up my variable if it's decimal larger than .3 and if it's lower or equal it will round down, for example if i have 1.34 it will round up to 2, if i have 1.29 it will round down to 1, and if i have 1.3 it will round down to 1. I don't know how to do this precisely, right now i'm using the round basic function like this:
$weight = $weight/1000;
if($weight < 1) $weight = 1;
else $weight = round($weight, 0, PHP_ROUND_HALF_DOWN);
If you manipulate the numbers a bit, you can figure out if the decimals are .3 or higher. You achieve this by flooring the value, and subtract that from the original value. Check if the result of that, multiplied by 10, is greater than 3. If it is, you've got something above x.3.
$number = 1.31;
$int = floor($number);
$float = $number-$int;
if ($float*10 > 3.1)
$result = ceil($number);
else
$result = $int;
echo $result; // 2
Live demo
I made you a little hack, here's the code
$weight = 5088;
$weight = $weight/1000;
if($weight < 1) {
$weight = 1;
} else {
// I get the last number (I treat the $weight as a string here)
$last_number = substr($weight, -1, 1);
// Then I get the precision (floating numbers)
$precision = strlen(substr(strrchr($weight, "."), 1));
// Then I convert it to a string so I can use some helpful string functions
$weight_str = (string) $weight;
// If the last number is less then 3
if ($last_number > 3)
// I change it to 9 I could just change it to 5 and it would work
// because round will round up if then number is 5 or greater
$weight_str[strlen($weight_str) -1] = 9;
}
}
// Then the round will round up if it's 9 or round down if it's 3 or less
$weight = round($weight_str, $precision);
echo $weight;
Maybe something like this function?
function roundImproved($value, $decimalBreakPart = 0.3) {
$whole = floor($value);
$decimal = $value - $whole;
$decimalPartLen = strlen($decimal) - 2;
return (number_format($decimal, $decimalPartLen) <= number_format($decimalBreakPart, $decimalPartLen) ? $whole : ceil($value));
}
Proof:
http://sandbox.onlinephpfunctions.com/code/d75858f175dd819de069a8a05611ac9e7053f07a
You can specify "break part" if you want.

PHP String to Int for MySQL Unique ID

I would like to convert a 17 digit unique ID retrieved as a string from my MYSQL database to a number. I use the int to do so. However I get a zero at the end:
$num = 96435171263250434;
(int)$num --> 96435171263250430
I've checked I am running a 64 bit system. I get the following:
php -r 'echo PHP_INT_MAX;'
9223372036854775807
How do I fix this issue???
You cannot exceed PHP_INT_MAX
$num = "96435171263250434";
$x = (float) $num; // This should hold it but it's a float
$maxIntMult = 0;
$maxIntMult = intval($x / PHP_INT_MAX);
$remainder = $x - $maxIntMult * PHP_INT_MAX;
echo PHP_INT_MAX . " x " .$maxIntMult. " + " . $remainder; // function of two integer if you can't work with floats and you can make something of this
You can try to make use of the fact that ids don't have negative values, effectively doubling your range.
$num = PHP_INT_MAX + 50;
$x = (float) $num;
$intX = $num - PHP_INT_MAX;
echo $intX; // Shows 50 with the '0' being -PHP_INT_MAX
function getIdWithNonZeroOffset($stringId)
{
$x = (float) $stringId;
$intX = $x - PHP_INT_MAX;
return $intX;
}
function getStringFromNonZeroOfssetId($id)
{
return (string) ($id + PHP_INT_MAX);
}
echo getIdWithNonZeroOffset((string)(PHP_INT_MAX + 200)); // Gives 200 (store this in int column)
echo getStringFromNonZeroOfssetId(200); // Gives "2147483847" (my max int is "2147483647")

How to round down to the nearest significant figure in php

Is there any slick way to round down to the nearest significant figure in php?
So:
0->0
9->9
10->10
17->10
77->70
114->100
745->700
1200->1000
?
$numbers = array(1, 9, 14, 53, 112, 725, 1001, 1200);
foreach($numbers as $number) {
printf('%d => %d'
, $number
, $number - $number % pow(10, floor(log10($number)))
);
echo "\n";
}
Unfortunately this fails horribly when $number is 0, but it does produce the expected result for positive integers. And it is a math-only solution.
Here's a pure math solution. This is also a more flexible solution if you ever wanted to round up or down, and not just down. And it works on 0 :)
if($num === 0) return 0;
$digits = (int)(log10($num));
$num = (pow(10, $digits)) * floor($num/(pow(10, $digits)));
You could replace floor with round or ceil. Actually, if you wanted to round to the nearest, you could simplify the third line even more.
$num = round($num, -$digits);
If you do want to have a mathy solution, try this:
function floorToFirst($int) {
if (0 === $int) return 0;
$nearest = pow(10, floor(log($int, 10)));
return floor($int / $nearest) * $nearest;
}
Something like this:
$str = (string)$value;
echo (int)($str[0] . str_repeat('0', strlen($str) - 1));
It's totally non-mathy, but I would just do this utilizing sting length... there's probably a smoother way to handle it but you could acomplish it with
function significant($number){
$digits = count($number);
if($digits >= 2){
$newNumber = substr($number,0,1);
$digits--;
for($i = 0; $i < $digits; $i++){
$newNumber = $newNumber . "0";
}
}
return $newNumber;
}
A math based alternative:
$mod = pow(10, intval(round(log10($value) - 0.5)));
$answer = ((int)($value / $mod)) * $mod;
I know this is an old thread but I read it when looking for inspiration on how to solve this problem. Here's what I came up with:
class Math
{
public static function round($number, $numberOfSigFigs = 1)
{
// If the number is 0 return 0
if ($number == 0) {
return 0;
}
// Deal with negative numbers
if ($number < 0) {
$number = -$number;
return -Math::sigFigRound($number, $numberOfSigFigs);
}
return Math::sigFigRound($number, $numberOfSigFigs);
}
private static function sigFigRound($number, $numberOfSigFigs)
{
// Log the number passed
$log = log10($number);
// Round $log down to determine the integer part of the log
$logIntegerPart = floor($log);
// Subtract the integer part from the log itself to determine the fractional part of the log
$logFractionalPart = $log - $logIntegerPart;
// Calculate the value of 10 raised to the power of $logFractionalPart
$value = pow(10, $logFractionalPart);
// Round $value to specified number of significant figures
$value = round($value, $numberOfSigFigs - 1);
// Return the correct value
return $value * pow(10, $logIntegerPart);
}
}
While the functions here worked, I needed significant digits for very small numbers (comparing low-value cryptocurrency to bitcoin).
The answer at Format number to N significant digits in PHP worked, somewhat, though very small numbers are displayed by PHP in scientific notation, which makes them hard for some people to read.
I tried using number_format, though that needs a specific number of digits after the decimal, which broke the 'significant' part of the number (if a set number is entered) and sometimes returned 0 (for numbers smaller than the set number).
The solution was to modify the function to identify really small numbers and then use number_format on them - taking the number of scientific notation digits as the number of digits for number_format:
function roundRate($rate, $digits)
{
$mod = pow(10, intval(round(log10($rate))));
$mod = $mod / pow(10, $digits);
$answer = ((int)($rate / $mod)) * $mod;
$small = strstr($answer,"-");
if($small)
{
$answer = number_format($answer,str_replace("-","",$small));
}
return $answer;
}
This function retains the significant digits as well as presents the numbers in easy-to-read format for everyone. (I know, it is not the best for scientific people nor even the most consistently length 'pretty' looking numbers, but it is overall the best solution for what we needed.)

Split a number by decimal point in php

How do I split a number by the decimal point in php?
I've got $num = 15/4; which turns $num into 3.75. I would like to split out the 3 and the 75 parts, so $int = 3 and $dec = 75. My non-working code is:
$num = 15/4; // or $num = 3.75;
list($int, $dec) = split('.', $num);
but that results in empty $int and $dec.
Thanks in advance.
If you explode the decimal representation of the number, you lose precision. If you don't mind, so be it (that's ok for textual representation). Take the locale into account! We Belgians use a comma (at least the non-programming ones :).
If you do mind (for computations e.g.), you can use the floor function:
$num = 15/4
$intpart = floor( $num ) // results in 3
$fraction = $num - $intpart // results in 0.75
Note: this is for positive numbers. For negative numbers you can invert the sign, use the positive approach, and reinvert the sign of the int part.
$num = 15/4; // or $num = 3.75;
list($int, $dec) = explode('.', $num);
Try explode
list($int,$dec)=explode('.', $num);
as you don't really need to use a regex based split. Split wasn't working for you as a '.' character would need escaping to provide a literal match.
$int = $num > 0 ? floor($num) : ceil($num);
$dec = $num - $int;
If you want $dec to be positive when $num is negative (like the other answers) you could do:
$dec = abs($num - $int);
$num = 3.75;
$fraction = $num - (int) $num;
In case when you don't want to lose precision, you can use these:
$number = 10.10;
$number = number_format($number, 2, ".", ",");
sscanf($number, '%d.%d', $whole, $fraction);
// you will get $whole = 10, $fraction = 10
This works for positive AND negative numbers:
$num = 5.7;
$whole = (int) $num; // 5
$frac = $num - (int) $num; // .7
$num = 15/4;
substr(strrchr($num, "."), 1)

Categories