3

I want to trim my decimal into something like 8.063 instead of the original which is 8.0638304611694E-9. I have implemented a function for it but it doesn't work when there is E-9 in it. Which part should I modify??

public function setPrecision($number, $decimals = 0)
{
    $negation = ($number < 0) ? (-1) : 1;
    $coefficient = 10 ** $decimals;
    return $negation * floor((string)(abs($number) * $coefficient)) / $coefficient;
}

EDIT

The current implementation gave me 0 when I try to call the function.

setPrecision(8.0638304611694E-9, 3); // 0
ADyson
  • 57,178
  • 14
  • 51
  • 63
Yura
  • 1,937
  • 2
  • 19
  • 47
  • 1
    https://www.php.net/manual/en/function.number-format.php ? https://www.php.net/manual/en/function.round.php ? If not then please make clear why they wouldn't work for you. – ADyson Dec 07 '21 at 12:48
  • number format doesn't seem to work properly with my numbers, and it also gave me 0.000. I'll update my question – Yura Dec 07 '21 at 12:49
  • 2
    In reality something like `8.0638304611694E-9` is `0.0000000080638304611694`. – KIKO Software Dec 07 '21 at 12:52
  • The result in your function call (edit) seems correct to me? You're rounding down, and like KIKO Software said your number is close to 0 in the 3rd decimal. – Torbjörn Stabo Dec 07 '21 at 12:56
  • I tried to use 12 as my `$decimals` parameter of the function, it works, but somehow it kept the `E-9` on the result. I want to completely remove it – Yura Dec 07 '21 at 12:56
  • Ok I think the issue is maybe just the tiny value of the number. When you try to round to 3 decimal places, it simply rounds it out of existence - demo: http://sandbox.onlinephpfunctions.com/code/4e118f865f804261dc67ee43441b1a8741a78fa1. The E is a red herring - that's just a presentation format (as KIKO Software has effectively pointed out already). – ADyson Dec 07 '21 at 12:59
  • @Tamma You could use number_format() for that. It returns a string though so you'd have to convert it back to a float. – Torbjörn Stabo Dec 07 '21 at 13:01
  • @TorbjörnStabo no, same issue it turns out. See my demo in the comment above. – ADyson Dec 07 '21 at 13:01
  • Your current implementation also produces `123.45` from `setPrecision(123.4567, 2)`. Do you need `1.23`? – Álvaro González Dec 07 '21 at 13:08
  • @ÁlvaroGonzález surely that would change the value, rather than simply altering the precision – ADyson Dec 07 '21 at 13:09
  • @ADyson He's asking just that for tiny numbers, thus my question. – Álvaro González Dec 07 '21 at 13:10
  • @ÁlvaroGonzález ah I see what you mean. I think though, from reading the question and the comments that maybe the OP hasn't quite understood the presentation format involving the E. I guess that's what you're hinting at? – ADyson Dec 07 '21 at 13:11
  • @ADyson Yes? I don't see what's wrong with the rounding in your demo? It's just a case of calculating the number of decimals correctly. – Torbjörn Stabo Dec 07 '21 at 13:12
  • @ÁlvaroGonzález is right, I'm confused by the E in the number and how to format it properly. I just want to get rid of that `E-9` and print only the number, with 3 decimal points ofc. – Yura Dec 07 '21 at 13:13
  • @TorbjörnStabo yes but you said "you could use number_format for that". By "that" I assumed, you meant the result the OP stated they wanted. But number_format doesn't produce what the OP wants (partly because it doesn't actually make a lot of sense) – ADyson Dec 07 '21 at 13:14
  • @ADyson It's getting too abstract here. number_format() can format the scientific notation value as an "ordinary float". Period. On the other hand it's totally possible that this might not be what OP wants. I'm not sure if OP understands the different notations or if that can be expressed in comment texts though. – Torbjörn Stabo Dec 07 '21 at 13:20
  • @TorbjörnStabo no I don't think they do. That's the nub of the issue, it turns out. See also comments on the answer below. – ADyson Dec 07 '21 at 13:20

2 Answers2

0

In PHP, there are (at the moment of writing) 8519 builtin functions. One of them probably does the trick!

You could use log10() and round() in your function:

function setPrecision($number, $precision = 0)
{
    $exponent = floor(log10($number)) - 1;
    return round($number, -$exponent + $precision - 1);
}

SteeveDroz
  • 6,006
  • 6
  • 33
  • 65
  • Note: the function could be optimized, but it is supposed to be readable. – SteeveDroz Dec 07 '21 at 13:03
  • This will output 8.064E-9, which isn't quite what the OP is looking for (although closer than anything else so far, admittedly) – ADyson Dec 07 '21 at 13:06
  • I tried it, as @ADyson pointed, it still printing the `E-9` in the number. How do I get rid of it? – Yura Dec 07 '21 at 13:10
  • @Tamma why exactly do you need/want to get rid of it? It's just a presentation format. The underlying number it represents is still the same. It's not something you need to worry about until you're trying to present the number to a human, really. A function to change the precision is a mathematical operation, not a presentation operation. As has been pointed out above, if you simply remove `E-9` from `8.063E-9` then you get `8.063` which is not the same number! – ADyson Dec 07 '21 at 13:13
  • @ADyson , the end result requires me to print just 8.063 without the E-9 in the UI – Yura Dec 07 '21 at 13:15
  • 2
    @Tamma but that would be misleading for the reader, because `8.063` is `8.063`, whereas `8.063E-9` is actually `0.000000008063`. Not the same thing. The `E...` format just provides a more compact way to write it down. If you round `0.000000008063` to 3 decimal places using conventional rounding, you get `0.000`, as I've already demonstrated. https://www.calculator.net/scientific-notation-calculator.html?cvtnum=8.063E-9&ctype=1&submit1=Convert – ADyson Dec 07 '21 at 13:16
  • @ADyson , Yes, I get your point. I think that is fine since this was a homework for my study in university, not a very critical project that needs the accurate result. The lecturer just told me to do it. If there is solution for it, I'll be very happy. – Yura Dec 07 '21 at 13:20
  • @Tamma there really isn't a solution because it doesn't make sense. Are you _sure_ that's what your lecturer told you to do? If so, they need a mathematics lesson. – ADyson Dec 07 '21 at 13:21
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/239909/discussion-between-tamma-and-adyson). – Yura Dec 07 '21 at 13:22
0

Relative rounding with a certain number of digits can easily be done with sprintf.

$round = (float)sprintf('%0.3E', 8.0638304611694E-9);
var_dump($round);  //float(8.064E-9)

On this basis I have this function which rounds float values with a certain relative decimal precision.

 /*
  * @return Float-Value with reduced precision
  * @param $floatValue: input (float)
  * @param $overallPrecision: 1..20 (default 10)
  */
  function roundPrecision($floatValue, $overallPrecision = 10)
  {
    $p = min(20,max(0,$overallPrecision-1));
    $f =(float)sprintf('%.'.$p.'e',$floatValue);
    return $f;
  }

example 1

  $float = 0.0000123456789;
  $newFloat = roundPrecision($float,5);
  printf('%0.10f',$newFloat);  //0.0000123460

example 2

  $float = 3456.7891234;
  $newFloat = roundPrecision($float,5);
  printf('%0.10f',$newFloat);  //3456.8000000000
jspit
  • 7,276
  • 1
  • 9
  • 17