Remove trailing zeros from decimal string - php

I have these numbers:
0.00000100
0.00100000
0.01000000
0.00001000
and I want to remove unnecessary zero in decimal by using this :
$decimal_cutter = (float) $decimal_cutter;
echo sprintf('%f', $decimal_cutter) . '<br>';
and it works for some numbers, some others produce this :
1.0E-6
0.001
0.01
1.0E-5
I want to use decimal, instead of scientific format.
Please note, I tried to use number_format() also, but keep in mind that by setting number of decimal points can cut the rest of numbers. I just want to remove the 0 after 1.

If you are simply worried about not displaying those characters, why not simply trim them?
You can simply call rtrim($yourNumber, '0')
E.g.:
$a = [];
$a[] = "0.00000100";
$a[] = "0.00100000";
$a[] = "0.01000000";
$a[] = "0.00001000";
foreach ($a as $b) {
echo rtrim($b, '0'), "\n";
}
Which outputs:
0.000001
0.001
0.01
0.00001
Logically this approach requires that you any of the decimal digits is different from 0, otherwise a number such as 2.0000 would be displayed as 2., which might not be ideal.
You could build a more general purpose solution using preg_replace
$a = [];
$a[] = "0.00000100";
$a[] = "0.00100000";
$a[] = "0.01000000";
$a[] = "0.00001000";
$a[] = "2.00000000";
$a[] = "2.01011000";
$a[] = "0.00123000";
foreach ($a as $b) {
echo preg_replace('|(?<!\.)0+$|', '', $b), "\n";
}
This looks for all trailing zeroes not preceded by a period, and would output:
0.000001
0.001
0.01
0.00001
2.0
2.01011
0.00123

Since you mention your data is always "1", here's a simple way:
$s = '0.00000100';
echo strstr($s, '1', true).'1';
Note: make sure you convert your data to string first

Related

How to convert decimals correctly after calculation [duplicate]

This question already has answers here:
Why is PHP printing my number in scientific notation, when I specified it as .000021?
(7 answers)
Closed 10 months ago.
I have the below problem, how to make it appear 0.00004 as string after multiplication?
$v = -0.00004;
$v = $v * -1;
echo $v; // 4.0E-5
Long story
As a result I need to save into MySQL database but no problem with that because I use below query:
$sql_insert = $conn->prepare("insert into tbl_transaction (amount) values ($v)");
However when I output to my HTML it showing 4.0E-5. I tried to use number_format but in some cases the decimals will go far more than this so it is not a choice.
Try this.
echo sprintf('%f', $v);
Or:
$b = sprintf('%f', $v);
echo $b;
You can try as below.
$v = -0.00004;
$v = $v * -1;
echo number_format($v, 5);
Hope this will help.
After formatting the number with the desired precision you need to strip the trailing zeros.
This should do the trick:
$v = -0.00004;
$v = number_format($v * -1, 20);
print rtrim($v, 0);
If you var_dump($v) after the first assignment, you'll see that the "problem" is NOT the calculation.
$v = -0.00004;
var_dump($v); //float(-4.0E-5)
number_format() can be used to return a formatted version of your value. You can get the length of the string value, and pass that to number_format.
var_dump(number_format($v,strlen(strval($v)))); // string(10) "-0.0000400"
So, your code would be:
$v = -0.00004;
$v = $v * -1;
$v = number_format($v,strlen(strval($v)));
echo $v //0.000040
You don't need to use number_format until you're ready to display the value because the exponential number is the same value as the formatted / decimal number.

How to compare key sequences from a large array, to find out the largest number of duplicate sequences?

I have already compared the data of a matrix, I have already counted the data of an array, but I have never counted, what is the repeated sequence of keys between the arrays, I want to make comparative between all sequences, and find out the maximum size of this section Repeated .. I have many hundreds of numbers that I should compare them between them, and find out the largest duplicate stretch between them, the maximum duplicity size that exists in a sequence, and that also exist in another sequence of the large array!
Finding repeating single elements can simply be done with in_array(). Repeating keys from different arrays is similarly easy with array_keys(). Neither really helps us since we are concerned with sequences, not single values.
<?php
header('Content-Type: text/html; charset=utf-8');
echo 'test - This is just for us to figure out, what is the size of the greatest duplication of stretches between the previous sequences'.'<br>';
$previous_results_manually_inserted = array(
array('12','21','34','1','51','87','42','49','37','119','101','7','111','17','11','19','2','15','6'),
array('3','5','1','18','61','75','92','84','36','81','2','07','90','2','71','17','08','51','37'),
array('81',75','92','84','36','81','2','07','90','2','17','65','44','73','27','30','41','74','88'),
);
foreach ( $previous_results_manually_inserted as $previous ) {
$match = preg_match("/.*$test.*/", $previous );
}
echo 'The largest repeated slice between these sequences is:';
echo implode(', ', $match ), "<br>\n"
output: 75','92','84','36','81','2','07','90','2'
Note: Final objective: the highest duplicity is 9 numbers. (In this example)
Thanks all.
The task is very similar to the algorithm for finding the largest common string. Can be solved as follows:
$arrs = [
['12','21','34','1','51','87','42','49','37','119','101','7','111','17','11','19','2','15','6'],
['3','5','1','18','61','75','92','84','36','81','2','07','90','2','71','17','08','51','37'],
['81','75','92','84','36','81','2','07','90','2','17','65','44','73','27','30','41','74','88'],
];
$sequence = [];
foreach($arrs as $offset => $item){
$sarr = array_slice($arrs , $offset+1);
$count = count($item);
foreach($sarr as $arr){
$str = join(',',$arr);
for($a = 0;$a<$count;$a++){
for($b = 1;$b<$count;$b++){
$needle = join(',',array_slice($item , $a , ($a + $b > $count ? $count : $b)));
if(strpos($str,$needle) !== false){
$sequence[(substr_count($needle,','))] = $needle;
}
}
}
}
}
echo array_pop($sequence).PHP_EOL;
//out : 75,92,84,36,81,2,07,90,2

Number permutations in PHP with repeated characters

I store a number in a string. My code shuffles the digits into different permutations.
Example if the input is:
'123'
then the output permutations will be:
123,132,213,231,321,312
If the input string has repeated digits, my code does not work, and goes into an infinite loop.
Example inputs that don't work:
11,22,33,44,55,455,998,855,111,555,888,222 etc.
My code:
<?php
function factorial($n){
if($n==1) return $n;
return $n*factorial($n-1);
}
$a = '1234';
$_a = str_split($a);
$num = count($_a);
$ele_amnt = factorial($num);
$output = array();
while(count($output) < $ele_amnt){
shuffle($_a);
$justnumber = implode('', $_a);
if(!in_array($justnumber , $output))
$output[] = $justnumber;
}
sort($output);
print_r($output);
Can anyone explain why and how to fix it?
Short version: Your terminating condition for the while loop "is" permutational while your if(!in_array...) test "is" combinational.
Let's assume $a=11;: then $ele_amnt is 2 and your while loop will stop when the array $output contains more than one element.
Your shuffle/implode code can produce either the string <firstelement><seconelement> or <secondelement><firstelement>, both being 11.
And if(!in_array( $justnumber , $output)) allows only one of them to be appended to $output. So count($output) will be 1 after the first iteration and will stay 1 in perpetuity. Same for every $a with duplicate digits.
shuffle() changes the position of elements in an array at random. SO, the performance of the algorithm depends on ....luck ;-)
You might be interested in something like https://pear.php.net/package/Math_Combinatorics instead.
Your output array will contain less permutations if you have repeated characters in your input. So your loop never completes.
You could map your inputs, then later map back from your output, and then filter to do as you desire:
// For a string '122' we get the permutations of '123' first and then process.
$output = op_code_no_repeats('123');
$filtered = array();
foreach($output as $permutation) {
$filtered[] = str_replace('3', '2', $permutation);
}
$filtered = array_unique($filtered);
var_dump($filtered);
Outputs:
array (size=3)
0 => string '122' (length=3)
2 => string '212' (length=3)
3 => string '221' (length=3)
Your code with guards on the factorial and permutation functions:
function factorial($n)
{
if(! is_int($n) || $n < 1)
throw new Exception('Input must be a positive integer.');
if($n==1)
return $n;
return $n * factorial($n-1);
};
function op_code_no_repeats($a) {
$_a = str_split($a);
if(array_unique($_a) !== $_a)
throw new Exception('Does not work for strings with repeated characters.');
$num = count($_a);
$perms_count = factorial($num);
$output = array();
while(count($output) < $perms_count){
shuffle($_a);
$justnumber = implode('', $_a);
if(!in_array($justnumber , $output))
$output[] = $justnumber;
}
sort($output);
return $output;
}

PHP Compress array of bits into shortest string possible

I have an array that contains values of 1 or 0 representing true or false values. e.g.
array(1,0,0,1,0,1,1,1,1);
I want to compress/encode this array into the shortest string possible so that it can be stored within a space constrained place such as a cookie. It also need to be able to be decoded again later. How do I go about this?
ps. I am working in PHP
Here is my proposal:
$a = array(1,0,0,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1);
$compressed = base64_encode(implode('', array_map(function($i) {
return chr(bindec(implode('', $i)));
}, array_chunk($a, 8))));
var_dump($compressed); // string(8) "l8vlBw=="
So you get each 8 characters (which in fact is a binary 0..255), convert them to an integer, represent as an ASCII character, implode it to a string and convert to base64 to be able to save it as a string.
UPD:
the opposite is pretty straightforward:
$original = str_split(implode('', array_map(function($i) {
return decbin(ord($i));
}, str_split(base64_decode($compressed)))));
How exactly I wrote it (just in case anyone interesting how to write such unreadable and barely maintainable code):
I've written the $original = $compressed; and started reversing the right part of this expression step by step:
Decoded from base64 to a binary string
Split it to an array
Converted every character to its ASCII code
Converted decimal ASCII code to a binary
Joined all the binary numbers into a single one
Split the long binary string to an array
Dont use serialize. Just make a string of it:
<?php
$string = implode( '', $array );
?>
You are left with an string like this:
100101111
If you want to have an array again, just access it like an array:
$string = '100101111';
echo $string[1]; // returns "0"
?>
Of course you could also make it a decimal and just store the number. That's even shorter then the "raw" bits.
<?php
$dec = bindec( $string );
?>
How about pack and unpack
$arr = array(1,1,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1,1,1,1);
$str = implode($arr);
$res = pack("h*", $str);
var_dump($res);
$rev = unpack("h*", $res);
var_dump($rev);
output:
string(10) # Not visible here
array(1) {
[1]=>
string(20) "11110011010011001111"
}
Here is my solution based on zerkms answer, this deals with the loss of leading 0's when converting decimals back into binary.
function compressBitArray(array $bitArray){
$byteChunks = array_chunk($bitArray, 8);
$asciiString = implode('', array_map(function($i) {
return chr(bindec(implode('', $i)));
},$byteChunks));
$encoded = base64_encode($asciiString).'#'.count($bitArray);
return $encoded;
}
//decode
function decompressBitArray($compressedString){
//extract origional length of the string
$parts = explode('#',$compressedString);
$origLength = $parts[1];
$asciiChars = str_split(base64_decode($parts[0]));
$bitStrings = array_map(function($i) {
return decbin(ord($i));
}, $asciiChars);
//pad lost leading 0's
for($i = 0; $i < count($bitStrings); $i++){
if($i == count($bitStrings)-1){
$toPad = strlen($bitStrings[$i]) + ($origLength - strlen(implode('', $bitStrings)));
$bitStrings[$i] = str_pad($bitStrings[$i], $toPad, '0', STR_PAD_LEFT);
}else{
if(strlen($bitStrings[$i]) < 8){
$bitStrings[$i] = str_pad($bitStrings[$i], 8, '0', STR_PAD_LEFT);
}
}
}
$bitArray = str_split(implode('', $bitStrings));
return $bitArray;
}

Most efficient way to create a 2d matrix from a 1d array in PHP

Given an array of strings, such as $a:
$a = array("zero", "one", "cat");
I'm looking to create array $b, populated "along the diagonal" with values from $a:
$b[0] = ["zero", "-", "-"]
$b[1] = ["-", "one", "-"]
$b[3] = ["-", "-", "cat"]
So far, I have:
function matrix($m, $n, $value) {
return array_fill(0, $m, array_fill(0, $n, $value));
} // create a matrix (m,n) of $value
$a = array("zero", "one", "cat");
$b = matrix(count($a),count($a),"'-'"); // create $b, filled with '-'
for($i = 0; $i < count($a); $i++){
$b[$i][$i] = $a[$i];
} // fill matrix b with strings from a, along the diagonal
print_r($b);
In practice $a is going to be quite large, so I'm looking for a method with the lowest chance of bringing a server to its knees.
(Extra thanks given if you explain your version as if I were 8 years old.)
A method that "does not bring a server to its knees" in my opinion would avoid function calls and would also not use recursion, even though both may look cleaner in terms of code. Either way, this is a fairly simple problem.
First, we create our dashes array:
$dashes = array_fill(0, count($a), array_fill(0, count($a), '-'));
You may notice a pattern based on dimensions:
0,0 1,0 2,0
0,1 1,1 2,1
0,2 1,2 2,2
Specifically, the X and Y coordinates match along the diagonal. That's handy because we only have to know one or the other to know the slot to insert into our dashes array. The index of the item in $a qualifies as either (and both):
foreach ($a as $num => $item) {
$dashes[$num][$num] = $item;
}
I don't know if is more efficient (you have to measure it with microtime()).
Use Array Fill maybe its easier to write or understand:
$a = array("zero", "one", "cat");
$elements=count($a);
//we create the matrix and fill it with "-"
$matrix=array_fill(0,$elements,array_fill(0,$elements,"-");)
//now we have a matrix $elements x $elements (in this case will be 3x3) filled by "-"
// - - -
// - - -
// - - -
And now we put the numbers
for($i = 0; $i < $elements; $i++){
$matrix[$i][$i] = $a[$i];
}

Categories