Como verificar se um valor flutuante é um número inteiro


202

Estou tentando encontrar a maior raiz do cubo que é um número inteiro, que é menor que 12.000.

processing = True
n = 12000
while processing:
    n -= 1
    if n ** (1/3) == #checks to see if this has decimals or not

Não sei como verificar se é um número inteiro ou não! Eu poderia convertê-lo em uma string e usar a indexação para verificar os valores finais e verificar se eles são zero ou não, o que parece bastante complicado. Existe uma maneira mais simples?


3
seria torná-lo mais fácil de trabalho a partir da raiz cúbica n -> (n * n * n <12000)
suspectus

Respostas:


367

Para verificar se um valor flutuante é um número inteiro, use o float.is_integer()método :

>>> (1.0).is_integer()
True
>>> (1.555).is_integer()
False

O método foi adicionado ao floattipo no Python 2.6.

Leve em consideração que no Python 2, 1/3é 0(divisão do piso para operandos inteiros!) E que a aritmética de ponto flutuante pode ser imprecisa (a floaté uma aproximação usando frações binárias, não um número real preciso). Mas ajustar um pouco o loop, isso dá:

>>> for n in range(12000, -1, -1):
...     if (n ** (1.0/3)).is_integer():
...         print n
... 
27
8
1
0

o que significa que qualquer coisa acima de 3 em cubos (incluindo 10648) foi perdida devido à imprecisão acima mencionada:

>>> (4**3) ** (1.0/3)
3.9999999999999996
>>> 10648 ** (1.0/3)
21.999999999999996

Você precisaria procurar números próximos ao número inteiro ou não usar float()para encontrar seu número. Como arredondar a raiz do cubo de 12000:

>>> int(12000 ** (1.0/3))
22
>>> 22 ** 3
10648

Se você estiver usando o Python 3.5 ou mais recente, poderá usar a math.isclose()função para verificar se um valor de ponto flutuante está dentro de uma margem configurável:

>>> from math import isclose
>>> isclose((4**3) ** (1.0/3), 4)
True
>>> isclose(10648 ** (1.0/3), 22)
True

Para versões mais antigas, a implementação ingênua dessa função (ignorando a verificação de erros e ignorando o infinito e o NaN), conforme mencionado em PEP485 :

def isclose(a, b, rel_tol=1e-9, abs_tol=0.0):
    return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

Não conhecendo python, esse tipo de afirmação me deixaria nervoso, pois parece exigir uma matemática perfeita para funcionar no mundo real.
Peter M

1
@ PeterM: O método realmente só retorna Truese não houver decimais. Pode haver um mal-entendido por parte do OP sobre aritmética e precisão de ponto flutuante, é claro.
Martijn Pieters

1
@MartijnPieters Sim e um pequeno deslize em um cálculo de ponto flutuante e, de repente, você tem esses pequenos, decimais indesejados como ,00000000000000000001
Peter M

1
@PeterM: e no Python 2 a representação padrão será arredondada para 16 dígitos; 1.0000000000000001é exibido como 1.0, em 3, a representação de string mais curta que produz o mesmo valor é mostrada.
Martijn Pieters

Seu range(12000, -1, -1)poderia ser (imo, mais limpa) reescrita comoreversed(range(12000+1))
cs95

36

Podemos usar o operador modulo (%). Isso nos diz quantos restos temos quando dividimos x por y - expressa como x % y. Cada número inteiro deve ser dividido por 1; portanto, se houver um restante, ele não deve ser um número inteiro.

Esta função retornará um valor booleano Trueou False, dependendo se né um número inteiro.

def is_whole(n):
    return n % 1 == 0

15

Você poderia usar isto:

if k == int(k):
    print(str(k) + " is a whole number!")

5
falha em números maiores enquanto .is_integer()continua a funcionar.
JFS

O seu link IMHO não mostra que não funciona. Isso apenas mostra que carros alegóricos grandes perdem precisão. is_integerusa um método semelhante ( o = (floor(x) == x) ? Py_True : Py_False;). Mas eu concordo, deve-se usar is_integer(), pois é muito mais claro.
perfil completo de Juri Robl

1
sim. Isso apenas mostra que a flutuação grande pode perder a precisão, ou seja, large_float == large_intpode falhar mesmo se large_float == float(large_int).
JFS

2
123456789012345678901234567890.0 != 123456789012345678901234567890mas123456789012345678901234567890.0 == float(123456789012345678901234567890)
jfs

2
Sim, mas k = 123456789012345678901234567890.0então k == int(k)é True, que é a resposta correta.
perfil completo de Juri Robl

9

Você não precisa fazer loop ou verificar nada. Basta pegar uma raiz cúbica de 12.000 e arredondar para baixo:

r = int(12000**(1/3.0))
print r*r*r # 10648

Esta é uma resposta razoável.
precisa saber é o seguinte

7

Você pode usar uma operação de módulo para isso.

if (n ** (1.0/3)) % 1 != 0:
    print("We have a decimal number here!")

2
se né 6.2, 6.0, 6.12312412, todos nós temos "We have a decimal number here!"?
Jay Wong

@ JayWong não tem certeza de como você carregou seu teste, mas isso funciona bem na minha máquina usando Python3.7.
precisa saber é o seguinte

6

Não seria mais fácil testar as raízes do cubo? Comece com 20 (20 ** 3 = 8000) e suba para 30 (30 ** 3 = 27000). Então você tem que testar menos de 10 números inteiros.

for i in range(20, 30):
    print("Trying {0}".format(i))
    if i ** 3 > 12000:
        print("Maximum integral cube root less than 12000: {0}".format(i - 1))
        break

1
Além disso, os flutuadores apresentam erros de arredondamento, para que você possa perder o número ao calcular se n**(1/3)é inteiro. Por exemplo, no meu computador, `10648 ** (1/3) = 21,999999999999996` em vez de 22: problem! Com o método desta resposta, não existe esse problema. Penso que esta é a única solução correta do ponto de vista matemático (outras soluções são corretas em Python).
JPG


3

As respostas acima funcionam para muitos casos, mas eles perdem alguns. Considere o seguinte:

fl = sum([0.1]*10)  # this is 0.9999999999999999, but we want to say it IS an int

Usando isso como referência, algumas das outras sugestões não obtêm o comportamento que podemos desejar:

fl.is_integer() # False

fl % 1 == 0     # False

Em vez disso, tente:

def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
    return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

def is_integer(fl):
    return isclose(fl, round(fl))

agora temos:

is_integer(fl)   # True

isclosevem com o Python 3.5+ e, para outros Python, você pode usar essa definição basicamente equivalente (conforme mencionado no PEP correspondente )


1
math.fsum([0.1] * 10) == 1
Acumenos

1

Apenas uma informação lateral, is_integerestá fazendo internamente:

import math
isInteger = (math.floor(x) == x)

Não exatamente em python, mas a implementação do cpython é implementada como mencionado acima.


1

Todas as respostas são boas, mas um método seguro de fogo seria

def whole (n):
     return (n*10)%10==0

A função retorna True se for um número inteiro False .... Eu sei que estou um pouco atrasada, mas aqui está um dos métodos interessantes que eu criei ...

Edit: como declarado no comentário abaixo, um teste equivalente mais barato seria:

def whole(n):
    return n%1==0

1
Isso não deve ser funcionalmente diferente de n % 1 == 0. Nesse caso, você está realizando duas operações que são mais caras para um teste equivalente mais barato.
Zchpyvr

0
>>> def is_near_integer(n, precision=8, get_integer=False):
...     if get_integer:
...         return int(round(n, precision))
...     else:
...         return round(n) == round(n, precision)
...
>>> print(is_near_integer(10648 ** (1.0/3)))
True
>>> print(is_near_integer(10648 ** (1.0/3), get_integer=True))
22
>>> for i in [4.9, 5.1, 4.99, 5.01, 4.999, 5.001, 4.9999, 5.0001, 4.99999, 5.000
01, 4.999999, 5.000001]:
...     print(i, is_near_integer(i, 4))
...
4.9 False
5.1 False
4.99 False
5.01 False
4.999 False
5.001 False
4.9999 False
5.0001 False
4.99999 True
5.00001 True
4.999999 True
5.000001 True
>>>

Aqui estão algumas diretrizes para Como redigir uma boa resposta? . Esta resposta fornecida pode estar correta, mas pode se beneficiar de uma explicação. As respostas apenas de código não são consideradas "boas". Da revisão .
Trenton McKinney

-1

Tente usar:

int(val) == val

Isso dará muito mais precisão do que qualquer outro método.


Você pode dar um exemplo para apoiar a afirmação de que "isso dará muito mais precisão"? Isso parece infundado.
Mark Dickinson

-1

Você pode usar a roundfunção para calcular o valor.

Sim, em python, como muitos apontaram quando calculamos o valor de uma raiz de cubo, ele fornecerá uma saída com um pouco de erro. Para verificar se o valor é um número inteiro, você pode usar a seguinte função:

def cube_integer(n):
    if round(n**(1.0/3.0))**3 == n:
        return True
    return False

Mas lembre-se de que isso int(n)é equivalente math.floore, por isso, se você encontrar o resultado int(41063625**(1.0/3.0)), receberá 344 em vez de 345.

Portanto, tenha cuidado ao usar as intraízes do cubo.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.