Vérifier si le flotteur est équivalent à une valeur entière en python
En Python 3, je suis de vérifier si une valeur donnée est triangulaire, qui est, il peut être représenté comme n(n+1)/2, pour un certain entier positif n
Je peux juste écrire:
import math
def is_triangular1(x):
num=(1/2) * (math.sqrt(8*x+1)-1 )
return int(num)==num
Ou dois-je le faire comme cela? :
epsilon = 0.000000000001
def is_triangular2(x):
num=(1/2) * (math.sqrt(8*x+1)-1 )
return abs(int(num) - num)<epsilon
J'ai vérifié que les deux fonctions renvoient les mêmes résultats pour x jusqu'à 1 000 000. Mais je ne suis pas sûr si généralement int(x) == x sera toujours correctement déterminer si un nombre est entier, parce que le cas lorsque, par exemple, 5 est représenté comme 4.99999999999997 etc.
Autant que je sache, la deuxième voie est la bonne, si je le fais en C, mais je ne suis pas sûr à propos de Python 3.
- Je sais que vous vous posez des questions à propos des flotteurs et des services de renseignements mais vous pouvez trouver la suite de Q utiles stackoverflow.com/questions/5595425/...
- Les deux fonctions peuvent renvoyer le même, mais pour une raison quelconque, ils retournent Vrai pour tous les nombres que j'ai essayé.
- êtes-vous à l'aide de Python3? En Python2
1/2==0
doncnum
sera toujours juste être0
- ah oui, je devrais lire plus attentivement
Vous devez vous connecter pour publier un commentaire.
Vous aurez envie de faire le dernier. Dans de la Programmation en Python 3 l'exemple suivant est donné comme le moyen le plus précis pour comparer
Aussi, depuis epsilon est la "plus petite différence, la machine peut distinguer entre deux nombres à virgule flottante", vous aurez envie d'utiliser <= dans votre fonction.
Modifier: Après avoir lu les commentaires ci-dessous, j'ai regardé en arrière à la livre, et plus particulièrement, elle a dit "Ici est une simple comparaison de la flotte pour l'égalité dans la limite de machines de précision". Je crois que c'était juste un exemple pour comparer les flotteurs d'une extrême précision, mais le fait que l'erreur est introduite avec beaucoup de flotteur de calculs ce qui devrait que rarement, voire jamais être utilisé. J'ai caractérisé comme le "plus précise" de façon à comparer dans ma réponse, qui en un sens est vrai, mais rarement à ce qui est prévu lors de la comparaison des flotteurs ou des entiers de flotteurs. Le choix d'une valeur (ex: 0.00000000001) basée sur le "domaine du problème" de la fonction au lieu d'utiliser sys.float_info.epsilon est la bonne approche.
Grâce à S. Lott et Sven Marnach pour leurs corrections, et je m'excuse si j'ai dirigé quiconque vers le bas le mauvais chemin.
5 - 4.999999999999997 <= sys.float_info.epsilon
est Faux (au moins sur mon python3.2 @64-bit)sys.float_info.epsilon
. Utiliser une valeur spécifique pour le domaine du problème.sys.float_info.epsilon
.epsilon = 0.000000000001
est plus susceptible d'être correct, car il dépend de quelque chose dans votre domaine de problème, pas assez arbitraire de la propriété de la représentation à virgule flottante.sys.float_info.epsilon
. Le code ci-dessus vérifie que l'erreur absolue, qui est simplement faux. Par exemple, comparer1011
et1011.0 / 7.0 * 7.0
à l'aide de votreequal_float()
fonction.abs(a - b) > 1
nous pourrions envisager les nombres égaux s'ils sont gros. Réitérer: FP numéros seulement ont une durée de relative erreur, alors queabs(a - b) > 1
est à nouveau une déclaration au sujet de la absolu d'erreur. Comme un exemple,a = 1e16
etb = 1e16 + 2.0
doit être considéré égal à FP de précision. Il est en fait pas represantable double précision nombre entre ces deux nombres.sys.float_info.epsilon
. Peut-être vous voulez lire le la norme de référence sur ce sujet.Il est
is_integer
fonction en python type float:Vos deux implémentations ont des problèmes. Il fait peut arriver que vous vous retrouvez avec quelque chose comme
4.999999999999997
, afin de l'utiliserint()
n'est pas une option.J'irais pour une approche complètement différente: d'Abord supposer que votre numéro est triangulaire, et de calculer ce que
n
serait dans ce cas. Dans cette première étape, vous pouvez compléter généreusement, car il est seulement nécessaire pour obtenir le résultat si le nombre qui est en est triangulaire. Ensuite, calculern * (n + 1) /2
pour cetten
, et comparer le résultat àx
. Maintenant, vous êtes à la comparaison de deux entiers, il n'y a pas d'inexactitudes gauche.Le calcul de
n
peut être simplifiée par l'expansion deet en utilisant que
positif
y
.round()
changé en Python 3.x. Mais étant donné que nous ne voulez arrondir les nombres qui sont assez proches des entiers, nous n'avons pas à vous inquiéter au sujet de l'affaire que la partie fractionnaire est exactement0.5
ici. Comme je l'ai dit avant, nous pouvons être assez tolérant avec l'arrondissement depuis que nous avons seulement besoin d'avoir droit si le nombre est en réalité triangulaire. C'est pourquoi il est aussi ok pour omettre le0.25
.((x*x+x)/2 for x in count())
et test de la fonction renvoie Vrai pour les ces et Faux pour tout le reste ... il n', pour tous les nombres Python peut se transformer en ints.Python n'ont
Decimal
classe (dans ledécimal
module), que vous pouvez utiliser pour éviter l'imprécision de la flotte.les flotteurs peuvent exactement représenter tous les entiers dans leur gamme - floating-point de l'égalité est difficile seulement si vous vous souciez de l'bits après la virgule. Donc, tant que tous les calculs dans votre formule de retour des nombres entiers pour le cas qui vous intéresse, int(num) == num est parfaitement sûr.
Donc, nous devons prouver que, pour tout nombre triangulaire, chaque morceau de maths vous ne peut être fait avec l'arithmétique des nombres entiers (et tout ce qui en sort est aussi un non-entier implique que x n'est pas triangulaire):
Pour commencer, nous pouvons supposer que x doit être un entier - ce qui est requis dans la définition de "triangulaire" nombre de.
Cela étant le cas, 8*x + 1 sera un entier, depuis les entiers sont fermés en vertu de + et * .
mathématiques.sqrt() retourne un float; mais si x est triangulaire, puis la racine carrée sera un nombre entier - c'est à dire, encore une fois exactement représentés.
Alors, pour tous x, qui doit retourner true dans vos fonctions, int(num) == num sera vrai, et si votre istriangular1 le sera toujours. Le seul point d'achoppement, comme mentionné dans les commentaires à la question, est-ce que Python 2 par défaut n'division entière de la même manière qu'en C - int/int => int, tronquer si le résultat ne peut pas être représenté exactement comme un int. Donc, 1/2 == 0. Ce problème est résolu en Python 3, ou en ayant la ligne
près du haut de votre code.
Je pense que le module décimal est ce que vous avez besoin
decimal
gère les problèmes de précision, et j'ai pensé que tout le monde a été assez formé en Python pour savoir où trouver de la documentation sur ce module, soit en cliquant sur Aide bouton à la position de RALENTI, soit sur python.org site (d'ailleurs tout le monde a sa préférence) - Concernant upvote, oh j'ai d'autres réponses ayant pas de points dans plusieurs threads, et j'ai encore bien dormir.Vous pouvez de votre tour de nombre, par exemple 14 décimales ou moins:
PS: double précision est d'environ 15 décimales
Il est difficile d'argumenter avec des normes.
En C99 et POSIX, le standard pour l'arrondi d'un float en int est défini par nearbyint() Le concept important est la direction de l'arrondissement et les paramètres régionaux spécifiques à l'arrondissement de la convention.
En supposant que la convention est commune de l'arrondissement, c'est le même que le C99 convention en Python:
Si vous voulez plus de contrôle sur l'arrondissement, pensez à utiliser le Décimal module et choisissez l'arrondissement à la convention que vous souhaitez employer. Vous souhaiterez peut-être utiliser L'Arrondi par exemple.
Une fois que vous avez décidé de la convention, arrondie à un int et de la comparer aux autres int.
Python utilise toujours la même représentation à virgule flottante et les opérations de C t, de sorte que la seconde est la voie correcte.
Sous le capot, le Python de type float est un C double.
Le plus robuste serait d'obtenir l'entier le plus proche de num, puis de tester si les entiers satisfait la propriété que vous recherchez:
round(num)
tours, mais renvoie un float.