web-dev-qa-db-fra.com

Division entière en awk

Je veux diviser deux nombres en awk, en utilisant une division entière, c'est-à-dire en tronquant le résultat. Par exemple

k = 3 / 2
print k

devrait imprimer 1

Selon le manuel ,

Division; parce que tous les nombres dans awk sont des nombres à virgule flottante, le résultat est non arrondi à un entier

Existe-t-il une solution de contournement pour obtenir une valeur entière?

La raison en est que je veux obtenir le élément central d'un tableau avec entier index [0 à num-1].

21
user000001

Utilisez la fonction int pour obtenir la partie entière du résultat, tronquée vers 0. Cela produit l'entier le plus proche du résultat, situé entre le résultat et 0. Par exemple, int(3/2) est 1 , int(-3/2) est -1.

Source: Le manuel AWK - Fonctions numériques

36
Gilles Quenot

Dans les cas simples, vous pouvez utiliser en toute sécurité int() qui tronque vers zéro1:

awk 'BEGIN { print int(3 / 2) }'    # prints 1
gawk 'BEGIN { print int(-3 / 2) }'  # prints -1; not guaranteed in POSIX awk

Gardez à l'esprit que awk utilise toujours des nombres à virgule flottante double précision2 et arithmétique à virgule flottante3, bien que. La seule façon d'obtenir des nombres entiers et de l'arithmétique entière est d'utiliser des outils externes, par ex. l'utilitaire standard expr:

awk 'BEGIN { "expr 3 / 2" | getline result; print result; }'    # prints 1

C'est vraiment awk ward, long, lent,… mais sûr et portable.


1 Dans POSIX awk , la troncature à zéro n'est garantie que pour les arguments positifs: int (x) - Retourne l'argument tronqué à un entier. La troncature doit être vers 0 lorsque x> 0. GNU awk (gawk) utilise la troncature vers zéro même pour les nombres négatifs: int (x) - Renvoie l'entier le plus proche à x, situé entre x et zéro et tronqué vers zéro. Par exemple, int (3) est 3, int (3.9) est 3, int (-3.9) est -3 et int (-3) est également -3.
2 Les expressions numériques sont spécifiées comme des flottants à double précision dans Expressions dans awk dans POSIX.
3 Toute l'arithmétique doit suivre la sémantique de l'arithmétique à virgule flottante telle que spécifiée par la norme ISO C (voir Concepts dérivés de la norme ISO C ). - awk POSIX: fonctions arithmétiques


Si vous choisissez d'utiliser des flotteurs, vous devez connaître leurs bizarreries et être prêt à les repérer et à éviter les bugs associés. Plusieurs exemples effrayants:

  • Numéros non représentables:

    awk 'BEGIN { x = 0.875; y = 0.425; printf("%0.17g, %0.17g\n", x, y) }'
    # prints 0.875, 0.42499999999999999
    
  • Erreurs d'arrondi accumulation:

    awk 'BEGIN{s=0; for(i=1;i<=100000;i++)s+=0.3; printf("%.10f, %d\n",s,int(s))}'
    # prints 29999.9999999506, 29999
    
  • Les erreurs d'arrondi ruinent les comparaisons:

    awk 'BEGIN { print (0.1 + 12.2 == 12.3) }'    # prints 0
    
  • La précision diminue avec l'amplitude, provoquant des boucles infinies:

    awk 'BEGIN { for (i=10^16; i<10^16+5; i++) printf("%d\n", i) }'
    # prints 10000000000000000 infinitely many times
    

En savoir plus sur le fonctionnement des flotteurs:

  1. Balises de débordement de pile virgule flottante wiki

  2. Article Wikipedia virgule flottante

  3. arithmétique de précision arbitraire GNU awk - contient à la fois des informations sur l'implémentation spécifique et des connaissances générales

8
Palec

La division sûre et rapide des entiers awk peut être effectuée avec:

q=(n-n%d)/d+(n<0)
7
Marijan Unetić