I have the following function (in PHP):
function FormatSize( $size ) {
$size = intval( $size );
$idx = 0;
$prefixes = array( "", "Ki", "Mi", "Gi", "Ti", "Pi" );
while( $size > 1024 ) {
$size = $size / 1024;
$idx++;
}
return sprintf( "%03.2f %sB", $size, $prefixes[$idx] );
}
and the following in lua
function GetSize( iSize )
local iSizeTemp, sPrefix, i = tonumber(iSize) or 0, {"", "Ki", "Mi", "Gi", "Ti", "Pi"}, 1
while iSizeTemp > 1024 do
iSizeTemp, i = iSizeTemp/1024, i+1
end
return string.format( "%03.2f %sB", iSizeTemp, sPrefix[i] )
end
The return statement uses %03.2f which should return the output as PQR.XY format, where P or Q or both can be zero.
But I'm getting a simple output (the same as %.2f) and the padding part (%03) seems to have no effect whatsoever. Here is the codepad link (for PHP and for Lua) for an example; where I'm passing a number 1285854482 to the function. The output comes to be 1.20 GiB instead of 001.20 GiB.
You seem to misundestand the description of %.f format specification: this - %03.2f - actually means 'allocate at least 3 symbols to represent a number, at least 2 of them for representing its non-integer part'. Note that full stop is not included into this 2 - but is included into 3, so this formatter never actually hits its 'minimum'. )
Change it into '%06.2f', and it'll work as you expect: of 6 symbols, 3 will be spent on a full stop symbol and two digits after, so 3 remain for representing the integer part of the number.
Ah. Found the solution after going through C++ reference on printf, which states about the number succeeding % sign as:
Minimum number of characters to be printed. If the value to be printed
is shorter than this number, the result is padded with blank spaces.
The value is not truncated even if the result is larger.
Related
Is there a way with number_format() to leave out decimal places if the number is not a float/decimal?
For example, I would like the following input/output combos:
50.8 => 50.8
50.23 => 50.23
50.0 => 50
50.00 => 50
50 => 50
Is there a way to do this with just a standard number_format()?
You can add 0 to the formatted string. It will remove trailing zeros.
echo number_format(3.0, 1, ".", "") + 0; // 3
A Better Solution: The above solution fails to work for specific locales. So in that case, you can just type cast the number to float data type. Note: You might loose precision after type casting to float, bigger the number, more the chances of truncating the number.
echo (float) 3.0; // 3
Ultimate Solution: The only safe way is to use regex:
echo preg_replace("/\.?0+$/", "", 3.0); // 3
echo preg_replace("/\d+\.?\d*(\.?0+)/", "", 3.0); // 3
Snippet 1 DEMO
Snippet 2 DEMO
Snippet 3 DEMO
If you want to use whitespace here is better solution
function real_num ($num, $float)
{
if (!is_numeric($num) OR is_nan($num) ) return 0;
$r = number_format($num, $float, '.', ' ');
if (false !== strpos($r, '.'))
$r = rtrim(rtrim($r, '0'), '.');
return $r;
}
Use:
$a = 50.00;
$a = round($a, 2);
Even though the number has 2 zeros trailing it, if you round it, it won't show the decimal places, unless they have some kind of value.
So 50.00 rounded using 2 places will be 50, BUT 50.23 will be 50.23.
Unless you specify at which point to round up or down, it won't change your decimal values. So just use default round()
I am in the position where I am trying to convert gigabytes to bytes from a submit form. I have searched around and I am unable to find anything suitable.
Currently when converting bytes to gigabytes I use this method, which works perfectly.
public function byteFormat($bytes, $unit = "", $decimals = 2)
{
$units = array('B' => 0, 'KB' => 1, 'MB' => 2, 'GB' => 3, 'TB' => 4,
'PB' => 5, 'EB' => 6, 'ZB' => 7, 'YB' => 8);
$value = 0;
if ($bytes > 0) {
// Generate automatic prefix by bytes
// If wrong prefix given
if (!array_key_exists($unit, $units)) {
$pow = floor(log($bytes)/log(1024));
$unit = array_search($pow, $units);
}
// Calculate byte value by prefix
$value = ($bytes/pow(1024,floor($units[$unit])));
}
// If decimals is not numeric or decimals is less than 0
// then set default value
if (!is_numeric($decimals) || $decimals < 0) {
$decimals = 2;
}
// Format output
return sprintf('%.' . $decimals . 'f '.$unit, $value);
}
There seems to be plenty of examples of bytes to other formats but not the other way around.
I have seen that I can convert the number 1.5 like so
round(($number[0] * 1073741824));
The result is 12992276070, however, when using the byteformat method shown above, I get the following 1610612736, this seems quite a difference between the two methods.
Can anyone suggest a more stable method for converting gigabytes to bytes.
Well there are two different unit symbol, decimal and binary.
As you can see here, decimal multiplication is by 1000 and binary by 1024.
so if you are using "B"(byte), just do something like:
$bytenumber=$giga*pow(1024,3);
if using "b"(bit) :
$bitnumber=$giga*pow(1000,3);
P.S:$giga is your giga number.
You can only get as accurate of a conversion as there are numbers after the decimal place. If you start with 1.29634 gigs you'll get a closer representation to it's actual byte value versus calling it 1.3 Gigs. Is that what you're after?
numberOfBytes = round (numberOfGb * 1073741824)
is the exact answer to your question. It seems, you have miscalculated. Try to check it on a calculator.
The other problem is that if you have the source number of 2 digits, it is incorrect to give an answer in more or less than 2 digits. The correct counting will be:
source: 1.5GB
counting: 1.5GB*1073741824 B/GB= 1610612736 B
rounding to the last significant digit: 1610612736 B ~= 1.6e9 B
answer: 1.6e9 B
But, of course, many clients do not really want the correct answer, they want THEIR answer. It is up to you to choose.
I wonder if is there a good way to get the number of digits in right/left side of a decimal number PHP. For example:
12345.789 -> RIGHT SIDE LENGTH IS 3 / LEFT SIDE LENGTH IS 5
I know it is readily attainable by helping string functions and exploding the number. I mean is there a mathematically or programmatically way to perform it better than string manipulations.
Your answers would be greatly appreciated.
Update
The best solution for left side till now was:
$left = floor(log10($x))+1;
but still no sufficient for right side.
Still waiting ...
To get the digits on the left side you can do this:
$left = floor(log10($x))+1;
This uses the base 10 logarithm to get the number of digits.
The right side is harder. A simple approach would look like this, but due to floating point numbers, it would often fail:
$decimal = $x - floor($x);
$right = 0;
while (floor($decimal) != $decimal) {
$right++;
$decimal *= 10; //will bring in floating point 'noise' over time
}
This will loop through multiplying by 10 until there are no digits past the decimal. That is tested with floor($decimal) != $decimal.
However, as Ali points out, giving it the number 155.11 (a hard to represent digit in binary) results in a answer of 14. This is because as the number is stored as something like 155.11000000000001 with the 32 bits of floating precision we have.
So instead, a more robust solution is needed. (PoPoFibo's solutions above is particularly elegant, and uses PHPs inherit float comparison functions well).
The fact is, we can never distinguish between input of 155.11 and 155.11000000000001. We will never know which number was originally given. They will both be represented the same. However, if we define the number of zeroes that we can see in a row before we just decide the decimal is 'done' than we can come up with a solution:
$x = 155.11; //the number we are testing
$LIMIT = 10; //number of zeroes in a row until we say 'enough'
$right = 0; //number of digits we've checked
$empty = 0; //number of zeroes we've seen in a row
while (floor($x) != $x) {
$right++;
$base = floor($x); //so we can see what the next digit is;
$x *= 10;
$base *= 10;
$digit = floor($x) - $base; //the digit we are dealing with
if ($digit == 0) {
$empty += 1;
if ($empty == $LIMIT) {
$right -= $empty; //don't count all those zeroes
break; // exit the loop, we're done
}
} else {
$zeros = 0;
}
}
This should find the solution given the reasonable assumption that 10 zeroes in a row means any other digits just don't matter.
However, I still like PopoFibo's solution better, as without any multiplication, PHPs default comparison functions effectively do the same thing, without the messiness.
I am lost on PHP semantics big time but I guess the following would serve your purpose without the String usage (that is at least how I would do in Java but hopefully cleaner):
Working code here: http://ideone.com/7BnsR3
Non-string solution (only Math)
Left side is resolved hence taking the cue from your question update:
$value = 12343525.34541;
$left = floor(log10($value))+1;
echo($left);
$num = floatval($value);
$right = 0;
while($num != round($num, $right)) {
$right++;
}
echo($right);
Prints
85
8 for the LHS and 5 for the RHS.
Since I'm taking a floatval that would make 155.0 as 0 RHS which I think is valid and can be resolved by String functions.
php > $num = 12345.789;
php > $left = strlen(floor($num));
php > $right = strlen($num - floor($num));
php > echo "$left / $right\n";
5 / 16 <--- 16 digits, huh?
php > $parts = explode('.', $num);
php > var_dump($parts);
array(2) {
[0]=>
string(5) "12345"
[1]=>
string(3) "789"
As you can see, floats aren't the easiest to deal with... Doing it "mathematically" leads to bad results. Doing it by strings works, but makes you feel dirty.
$number = 12345.789;
list($whole, $fraction) = sscanf($number, "%d.%d");
This will always work, even if $number is an integer and you’ll get two real integers returned. Length is best done with strlen() even for integer values. The proposed log10() approach won't work for 10, 100, 1000, … as you might expect.
// 5 - 3
echo strlen($whole) , " - " , strlen($fraction);
If you really, really want to get the length without calling any string function here you go. But it's totally not efficient at all compared to strlen().
/**
* Get integer length.
*
* #param integer $integer
* The integer to count.
* #param boolean $count_zero [optional]
* Whether 0 is to be counted or not, defaults to FALSE.
* #return integer
* The integer's length.
*/
function get_int_length($integer, $count_zero = false) {
// 0 would be 1 in string mode! Highly depends on use case.
if ($count_zero === false && $integer === 0) {
return 0;
}
return floor(log10(abs($integer))) + 1;
}
// 5 - 3
echo get_int_length($whole) , " - " , get_int_length($fraction);
The above will correctly count the result of 1 / 3, but be aware that the precision is important.
$number = 1 / 3;
// Above code outputs
// string : 1 - 10
// math : 0 - 10
$number = bcdiv(1, 3);
// Above code outputs
// string : 1 - 0 <-- oops
// math : 0 - INF <-- 8-)
No problem there.
I would like to apply a simple logic.
<?php
$num=12345.789;
$num_str="".$num; // Converting number to string
$array=explode('.',$num_str); //Explode number (String) with .
echo "Left side length : ".intval(strlen($array[0])); // $array[0] contains left hand side then check the string length
echo "<br>";
if(sizeof($array)>1)
{
echo "Left side length : ".intval(strlen($array[1]));// $array[1] contains left hand check the string length side
}
?>
What does the "B" do in this pack statement from Perl code?
$hce_hash=pack('B*', $hce_hash);
Is there an equivalent function in PHP?
PHP’s pack doesn’t support a format of B*, but it does support H*. In Perl, you could emulate it with
sub pack_Bstar {
my($bits) = #_;
my $Hstar;
my $nybble = 0;
for (my $i = 0; $i < length $bits; ++$i) {
$nybble *= 2;
$nybble += int substr($bits, $i, 1);
if ($i % 4 == 3) {
$Hstar .= sprintf "%x", $nybble;
$nybble = 0;
}
}
my $pad = 4 - length($bits) % 4;
if ($pad != 4) {
$nybble = ($nybble << $pad);
$Hstar .= sprintf "%x", $nybble;
}
pack "H*", $Hstar;
}
The code above is not idiomatic Perl, but translation to PHP should be straightforward.
The H* format wants a hex string with high nybble (4 bits) first. The code above chews off four bits at a time to compute each nybble value. For example, for a bit string of 1011, tracing the algorithm gives
nybble = 0
nybble = 2 * 0 + 1 = 1
nybble = 2 * 1 + 0 = 2
nybble = 2 * 2 + 1 = 5
nybble = 2 * 5 + 1 = 11
10112 is indeed 1110, which is b16. If the last nybble is incomplete (between one and three bits), we left-shift the bit the appropriate number of places. This has the effect of zero-padding on the right.
Tests:
my #tests = (
["01001010011101010111001101110100" => "Just"],
["0110000101101110011011110111010001101000011001010111001" => "another"],
["01010000010010000101000000101111010100000110010101110010011011" => "PHP/Perl"],
["01101000011000010110001101101011011001010111001000101100" => "hacker,"],
);
for (#tests) {
my($input,$expect) = #$_;
my $got = pack_Bstar $input;
print "$input: ", ($got eq $expect ? "PASS" : "FAIL"), " ($got)\n";
}
Output:
01001010011101010111001101110100: PASS (Just)
0110000101101110011011110111010001101000011001010111001: PASS (another)
01010000010010000101000000101111010100000110010101110010011011: PASS (PHP/Perl)
01101000011000010110001101101011011001010111001000101100: PASS (hacker,)
pack 'B*', $s returns the bytes represented by the string of 0 and 1 characters that form up the string in $s. The value of $s is right-padded with zeros to a length divisible by 8 if necessary.
For example,
pack 'B*', '0100101000110101'
results in
chr(0b01001010) . chr(0b00110101);
As others have noted, PHP's pack() does not support the B template, which in Perl's pack() turns a bitstring, represented as a literal string of 0 and 1 characters, into a packed byte string with 8 bits per byte.
However, since PHP's pack() does support the H template, which does the same except for hexadecimal digits instead of bits, we can emulate Perl's B template in PHP by first using base_convert() to turn the bits into hex digits and then packing those:
function pack_B( $bits, $len = false ) {
// truncate input to desired length, if given:
if ( $len === false ) $len = strlen( $bits );
else $bits = substr( $bits, 0, $len );
// pad input with zeros to next multiple of 4 above $len:
$hexlen = (int)( ($len + 3) / 4 );
$bits = str_pad( $bits, 4*$hexlen, "0" );
// split input into chunks of 4 bits, convert each to hex and pack them:
$nibbles = str_split( $bits, 4 );
foreach ( $nibbles as $i => $nibble ) {
$nibbles[$i] = base_convert( $nibble, 2, 16 );
}
return pack( "H*", implode( "", $nibbles ) );
}
(The reason we can't just feed the whole input string to base_convert() is that it stores its intermediate result as a PHP float, and thus doesn't produce correct results for numbers too large to be accurately represented by a float. Doing it one hex digit at a time works fine, however.)
given a script that generates a string of 12 characters randomly generated, how many possibilities there are for two string to be equal?
function rand_string( $length ) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$size = strlen( $chars );
for( $i = 0; $i < $length; $i++ ) {
$str .= $chars[ rand( 0, $size - 1 ) ];
}
return $str;
}
Assuming, A-Za-z0-9, there are 62 possible character values. Therefore, there are 62^12 (to-the-power-of) possible strings. That's roughly 3x10^21 (3 with 21 zeros).
Assuming a perfect random number generator, that's a 1 in 3x10^21 chance that any two particular strings will be equal.
Given that code and a length of 12, there are 6212 possible values. So (assuming a perfectly uniform random number generator, which rand() probably isn't) the chances are 1 in 3226266762397899821056 that a single call to that function will return any arbitrary 12-character string.
OTOH, if you are calling the function repeatedly and want to know how long until you are likely to get a repeat of any previously returned value, you would have to call it about 6.7e+10 times to have a 50% chance of a collision (again, assuming a uniform random number generator). You can get a reasonable approximation of the number of calls required for any collision probability p between 0 and 1 by calculating sqrt(-ln(1 - p) * 2 * 6212).
This falls under the Birth Paradox (how many people do you need in a room to have a 50% chance of two or more people having the same birthday).
Your 12-long 62-char strings come out to be about 72 bits. With the approximate detailed here, you can expect to generate about SQRT((pi / 2) * 62^12)) = 7.112x10^10 strings before getting a collision. So about 1 in 70 billion.