Como obter a parte inteira e decimal de um número?

98

Dado, digamos, 1,25 - como obtenho "1" e "25" partes desse número?

Preciso verificar se a parte decimal é 0,0, 0,25, 0,5 ou 0,75.

StackOverflowNewbie
fonte
Será que uma simples explosão funcionará? $ splitDec = explode (".", $ decimal); $ splitDec [0] agora será 1 e splitDec [1] agora será 25 de seu exemplo.
Matt
@Matt split()foi preterido.
alex
@alex sim, esqueci. Estava pensando em javascript. alterado para explodir.
Matt
@Matt, split foi descontinuado a partir do PHP 5.3 e, na verdade, leva um regex como argumento, enquanto explodir leva uma string. explode () é o preferido neste caso.
shelhamer
4
Esteja ciente de que explode(".",1.10);darei 1 e 1, não 1 e 10
Michel

Respostas:

177
$n = 1.25;
$whole = floor($n);      // 1
$fraction = $n - $whole; // .25

Em seguida, compare com 1/4, 1/2, 3/4, etc.


Em casos de números negativos, use o seguinte:

function NumberBreakdown($number, $returnUnsigned = false)
{
  $negative = 1;
  if ($number < 0)
  {
    $negative = -1;
    $number *= -1;
  }

  if ($returnUnsigned){
    return array(
      floor($number),
      ($number - floor($number))
    );
  }

  return array(
    floor($number) * $negative,
    ($number - floor($number)) * $negative
  );
}

O $returnUnsignedpára-lo de fazer -1.25 para -1 & -0.25

Brad Christie
fonte
7
Como um lado, intval()ou elenco simples (int)pode ter mais desempenho do quefloor()
Jason McCreary
1
Como o piso contabiliza os negativos?
LanceH
@LanceH: Não, mas você pode lidar com isso facilmente com um sinalizador negativo.
Brad Christie
4
Esta resposta é realmente imprecisa, a menos que você adicione uma rodada (). Parece idiota, eu sei, mas tem a ver com aritmética de número de ponto flutuante de baixo nível. Veja aqui: stackoverflow.com/questions/3726721/php-math-precision
Matt James
Tente com 510,9, retorna 0,89. Mas não posso dizer por quê.
T30 de
38

Este código irá dividi-lo para você:

list($whole, $decimal) = explode('.', $your_number);

onde $ inteiro é o número inteiro e $ decimal terá os dígitos após o ponto decimal.

shelhamer
fonte
9
Esteja ciente de que explode(".",1.10);darei 1 e 1, não 1 e 10
Michel
3
Isso interrompe e lança um aviso sobre o índice indefinido, se o número for inteiro ou não contiver parte decimal.
Andreyco
1
Isso pressupõe que o número não acabará sendo representado em notação científica quando convertido em string. Se for um número realmente muito grande ou muito pequeno, então esse não será o caso e esse método falhará.
GordonM
20

Só para ser diferente :)

list($whole, $decimal) = sscanf(1.5, '%d.%d');

CodePad .

Como um benefício adicional, ele só será dividido quando os dois lados consistirem em dígitos.

alex
fonte
2
Este não quebra se o número não contém parte decimal. Ótimo!
Andreyco
É bom que isso produza dois inteiros; em vez de um int e um float.
foochow de
1
Isso pressupõe que o número não acabará sendo representado em notação científica quando convertido em string. Se for um número realmente muito grande ou muito pequeno, então esse não será o caso e esse método falhará.
GordonM
18

O método floor () não funciona para números negativos. Isso sempre funciona:

$num = 5.7;
$whole = (int) $num;  // 5
$frac  = $num - $whole;  // .7

... também funciona para negativos (mesmo código, número diferente):

$num = -5.7;
$whole = (int) $num;  // -5
$frac  = $num - $whole;  // -.7
a dude
fonte
8

um caminho curto (use floor e fmod)

$var = "1.25";
$whole = floor($var);     // 1
$decimal = fmod($var, 1); //0.25

em seguida, compare $ decimal com 0, 0,25, 0,5 ou 0,75

mpalencia
fonte
Eu aceito essa resposta! É próximo ao C # (a % 1)e trata bem os números negativos.
Bitterblue
7

Lance como um int e subtraia

$integer = (int)$your_number;
$decimal = $your_number - $integer;

Ou apenas para obter o decimal para comparação

$decimal = $your_number - (int)$your_number
Dom
fonte
5

Também existe uma função fmod que pode ser usada: fmod ($ my_var, 1) retornará o mesmo resultado, mas às vezes com um pequeno erro de arredondamento.

ip512
fonte
3

PHP 5.4+

$n = 12.343;
intval($n); // 12
explode('.', number_format($n, 1))[1]; // 3
explode('.', number_format($n, 2))[1]; // 34
explode('.', number_format($n, 3))[1]; // 343
explode('.', number_format($n, 4))[1]; // 3430
Vasil Nikolov
fonte
2

Esta é a maneira que eu uso:

$float = 4.3;    

$dec = ltrim(($float - floor($float)),"0."); // result .3
Serdar Değirmenci
fonte
1

O método de Brad Christie é essencialmente correto, mas pode ser escrito de forma mais concisa.

function extractFraction ($value) 
{
    $fraction   = $value - floor ($value);
    if ($value < 0)
    {
        $fraction *= -1;
    }

    return $fraction;
}

Isso é equivalente ao seu método, mas mais curto e, felizmente, mais fácil de entender como resultado.

GordonM
fonte
1
$x = 1.24

$result = $x - floor($x);

echo $result; // .24
Stnfordly
fonte
1

Se você pode contar com sempre 2 casas decimais, você pode apenas usar uma operação de string:

$decimal = 1.25;
substr($decimal,-2);  // returns "25" as a string

Nenhuma ideia de desempenho, mas para o meu caso simples, isso era muito melhor ...

Ben Barreth
fonte
Nota: se você fizer isso, você deve pelo menos usar round ($ decimal, 2); primeiro, para garantir que você tenha apenas dois dígitos decimais. Mas você não pode usar isso se quiser ter matemática correta ou lidar com dinheiro.
Ulrik McArdle
0

Para evitar o decimal flutuante extra (ou seja, 50,85 - 50 dê 0,850000000852), no meu caso, preciso apenas de 2 decimais para centavos monetários.

$n = 50.85;
$whole = intval($n);
$fraction = $n * 100 % 100;
fbaudet
fonte
0

Eu estava tendo dificuldade em encontrar uma maneira de separar o valor em dólares do valor após a casa decimal. Acho que descobri principalmente e pensei em compartilhar se algum de vocês estava tendo problemas

Então, basicamente...

se o preço for 1234,44 ... todo seria 1234 e o decimal seria 44 ou

se o preço for 1234,01 ... todo seria 1234 e o decimal seria 01 ou

se o preço for 1234,10 ... o todo seria 1234 e o decimal seria 10

e assim por diante

$price = 1234.44;

$whole = intval($price); // 1234
$decimal1 = $price - $whole; // 0.44000000000005 uh oh! that's why it needs... (see next line)
$decimal2 = round($decimal1, 2); // 0.44 this will round off the excess numbers
$decimal = substr($decimal2, 2); // 44 this removed the first 2 characters

if ($decimal == 1) { $decimal = 10; } // Michel's warning is correct...
if ($decimal == 2) { $decimal = 20; } // if the price is 1234.10... the decimal will be 1...
if ($decimal == 3) { $decimal = 30; } // so make sure to add these rules too
if ($decimal == 4) { $decimal = 40; }
if ($decimal == 5) { $decimal = 50; }
if ($decimal == 6) { $decimal = 60; }
if ($decimal == 7) { $decimal = 70; }
if ($decimal == 8) { $decimal = 80; }
if ($decimal == 9) { $decimal = 90; }

echo 'The dollar amount is ' . $whole . ' and the decimal amount is ' . $decimal;
Julie
fonte
-1

Não vi um módulo simples aqui ...

$number         = 1.25;
$wholeAsFloat   = floor($number);   // 1.00
$wholeAsInt     = intval($number);  // 1
$decimal        = $number % 1;      // 0.25

Nesse caso, obter os dois $wholeAs?e $decimalnão depender do outro. (Você pode pegar 1 das 3 saídas independentemente.) Eu mostrei $wholeAsFloate $wholeAsIntporquefloor() retorna um número do tipo flutuante, embora o número que ele retorna seja sempre inteiro. (Isso é importante se você estiver passando o resultado para um parâmetro de função com dica de tipo.)

Eu queria que isso dividisse um número de ponto flutuante de horas / minutos, por exemplo, 96,25, em horas e minutos separadamente para uma instância DateInterval como 96 horas e 15 minutos. Eu fiz isso da seguinte maneira:

$interval = new \DateInterval(sprintf("PT%dH%dM", intval($hours), (($hours % 1) * 60)));

Eu não me importei com segundos no meu caso.

Adambiano
fonte
-3
val = -3.1234

fraction = abs(val - as.integer(val) ) 
Guido C
fonte
2
Olá, adicione um pouco de explicação junto com o código, pois ajuda a entender seu código. Respostas apenas em código são desaprovadas.
Bhargav Rao