[RUBY] J'ai essayé de savoir ce qui se passerait si je convertissais NaN ou INF en int

Que se passe-t-il si vous convertissez un non-nombre ou l'infini à virgule flottante en int dans divers systèmes de traitement.

L'environnement est principalement macOS Mojave 10.14.2. Seuls cl.exe (langage C) et C # sont Windows 10 (64 bits). Les deux ont un processeur x64.

Je suis curieux de savoir ce qui se passe avec ARM, mais je n'ai pas d'environnement sous la main. Souhaitez-vous écrire un article?

Langage C

Le code source est comme ça

c99


#include <stdio.h>

double div(double x, double y ){
  return x/y;
}

int main()
{
  double nan = div(0.0,0.0);
  double pinf = div(1.0, 0.0);
  double minf = -pinf;
  printf("%f | %f | %f |\n", nan, pinf, minf);
  printf("%d | %d | %d |\n", (int)nan, (int)pinf, (int)minf);
  return 0;
}

Sentiment.

Système de traitement NaN +INF -INF
clang-1000.11.45.5 -2147483648 -2147483648 -2147483648
gcc-8 (Homebrew GCC 8.2.0) 8.2.0 -2147483648 -2147483648 -2147483648
cl.exe 19.16.27025.1 -2147483648 -2147483648 -2147483648

Je pense que c'est un "comportement indéfini" en langage C.

Pour clang et gcc, c'est un MacBookPro 2015, donc x64. cl.exe (Visual Studio) est également x64. N'a pas construit sur x86.

À propos, div est une fonction car` double nan = 0.0 / 0.0; ʻest cl.exe et provoque une erreur de compilation. J'obtiens une erreur au moment de la compilation mais nan au moment de l'exécution.

ruby

Le code source est comme ça

ruby


def toi(f)
  begin
    f.to_i
  rescue => e
    e.inspect.gsub( /\W+/, " " ).strip
  end
end

values = [Float::NAN, Float::INFINITY, -Float::INFINITY]
puts values.map{ |f| toi(f).inspect }.join("|")

Sentiment.

Système de traitement NaN +INF -INF
ruby 2.5.3p105 "FloatDomainError NaN" "FloatDomainError Infinity" "FloatDomainError Infinity"
jruby 9.2.0.0 (2.5.0) "FloatDomainError NaN" "FloatDomainError Infinity" "FloatDomainError Infinity"

Étonnamment une exception.

En jruby, bien sûr, avec ruby, le résultat sera différent de java (décrit plus loin). Est-ce naturel?

python

Le code source est comme ça

python2or3


import sys
import re
import numpy as np

def toi(f):
  try:
    return int(f)
  except:
    return re.sub( r"\W+", " ", str(sys.exc_info()[0]) )

nan = float("nan")
pinf = float("inf")
minf = -pinf
ints = [ toi(x) for x in [ nan, pinf, minf ] ]
print( "|".join( ints ) )

npa = np.array([nan, pinf, minf])
print( npa.astype("int32"))

Sentiment.

Système de traitement veux dire NaN +INF -INF
Python 3.7.1 int() class ValueError class OverflowError class OverflowError
Python 2.7.15 int() type exceptions ValueError type exceptions OverflowError type exceptions OverflowError
Python 3.7.1 .astype("int32") -2147483648 -2147483648 -2147483648
Python 2.7.15 .astype("int32") -2147483648 -2147483648 -2147483648

Exception lorsqu'elle est faite avec int (). Eh bien c'est vrai. Avec numpy, il n'y a pas de temps pour lancer une exception. C'est devenu la même chose que le langage C.

go

Le code source est comme ça

go


package main

import (
	"fmt"
	"math"
)

func main() {
	nan := math.NaN()
	pinf := math.Inf(1)
	minf := math.Inf(-1)
	fmt.Printf("%d|%d|%d|\n", int32(nan), int32(pinf), int32(minf))
}

Sentiment.

Système de traitement NaN +INF -INF
go1.11.2 darwin/amd64 -2147483648 -2147483648 -2147483648

Faire paniquer est exagéré, et il n'y a pas d'exceptions, il n'y a donc pas d'autre choix que d'en faire une valeur étrange comme en langage C.

Selon Go Programming Language Specification

Pour toutes les conversions non constantes contenant des valeurs à virgule flottante ou des nombres complexes, si le type résultant ne peut pas représenter une valeur, la conversion proprement dite réussira, mais la valeur résultante dépendra de l'implémentation.

Cela semble donc dépendre de la mise en œuvre.

C#

Le code source est comme ça

C#


using System;

namespace NanToInt
{
    class M
    {
        static void Main()
        {
            double nan = double.NaN;
            double pinf = double.PositiveInfinity;
            double minf = double.NegativeInfinity;
            int inan = (int)nan;
            int ipinf = (int)pinf;
            int iminf = (int)minf;
            Console.WriteLine( "{0}|{1}|{2}|", inan, ipinf, iminf );
        }
    }
}

Sentiment.

Système de traitement NaN +INF -INF
csc 2.10.0.0 -2147483648 -2147483648 -2147483648

Ce sera la même valeur que clang et gcc sans exception.

Au fait (decimal)double.NaN Si vous le faites, un message légèrement inapproprié "System.OverflowException: La valeur de type Decimal est trop grande ou trop petite." Est une exception.

Java

Le code source est comme ça

Java1.8


class NanToIntTest {
  public static void main( String[] args ){
    int inan = (int)Double.NaN;
    int ipinf = (int)Double.POSITIVE_INFINITY;
    int iminf = (int)Double.NEGATIVE_INFINITY;
    System.out.printf("%d|%d|%d\n", inan, ipinf, iminf);
  }
}

Sentiment.

J'ai écrit " public static void main "après un long moment.

Système de traitement NaN +INF -INF
java version "1.8.0_60" 0 2147483647 -2147483648

Java ne fait pas exception. La valeur est différente de clang, gcc et go.

Au fait, new BigDecimal (Double.NaN); est une exception de " java.lang.NumberFormatException: Infinite ou NaN ".

groovy

Le code source est comme ça

int inan = (int)Double.NaN;
int ipinf = (int)Double.POSITIVE_INFINITY;
int iminf = (int)Double.NEGATIVE_INFINITY;
printf("%d|%d|%d\n", inan, ipinf, iminf);

Sentiment.

Système de traitement NaN +INF -INF
Groovy Version: 2.5.4 JVM: 1.8.0_60 0 2147483647 -2147483648

Il donne toujours le même résultat que Java.

JavaScript(nodejs)

javascript:node-v11.3.0


var values = [0.0 / 0.0, 1.0 / 0.0, -1.0 / 0.0]
console.log(["or op."].concat(values.map(x => x | 0)).join("|"))
console.log(["and op."].concat(values.map(x => x & 0xffffffff)).join("|"))
function u16a(x){
  a = new Uint16Array(1);
  a[0] = x;
  return a[0];
}
function i16a(x){
  a = new Int16Array(1);
  a[0] = x;
  return a[0];
}
console.log(["u16a"].concat(values.map(x=>u16a(x))).join("|"))
console.log(["i16a"].concat(values.map(x=>i16a(x))).join("|"))

Le système de traitement est la version 11.3.0 de node.js.

veux dire NaN +INF -INF
or op. 0 0 0
and op. 0 0 0
u16a 0 0 0
i16a 0 0 0

Si vous essayez d'en faire un entier 32 bits, ou si vous plongez dans un type entier avec un nombre limité de bits, ce sera zéro. Si vous faites quelque chose comme math.floor (x), ce sera NaN ou ʻInfinity`, donc ce n'est pas intéressant.

Rust

Le code source est comme ça

rust


fn main() {
    let nan = std::f64::NAN;
    let pinf = std::f64::INFINITY;
    let minf = -std::f64::INFINITY;
    println!("{}|{}|{}", nan as i32, pinf as i32, minf as i32);
}

Sentiment.

Étonnamment aucune exception. Le résultat est

Système de traitement NaN +INF -INF
rustc 1.30.1 -2147483648 -2147483648 -2147483648

Cependant, selon Cast between types

** Remarque: Actuellement, cette conversion provoque un comportement indéfini si la valeur arrondie ne peut pas être gérée par le type entier de destination. ** Cela comprend Inf et NaN. Ceci est un bug et sera corrigé.

Il semble qu'il sera ** corrigé **.

PHP

Le code source est comme ça

php7


<?php
$nan = 0.0/0.0;
$pinf = 1.0/0.0;
$minf = -1.0/0.0;
echo( join("|", [ (int)$nan, (int)$pinf, (int)$minf ])."\n" );
echo( join("|", [ intval($nan), intval($pinf), intval($minf) ])."\n" );
?>

Je me demande si ça fait du bien. Je ne sais pas.

Le résultat est surprenant

Système de traitement veux dire NaN +INF -INF
PHP 7.1.19 (int) 0 0 0
PHP 7.1.19 intval() 0 0 0

Et tout devient nul.

perl

Le code source est comme ça

perl


use strict;
use warnings;

my $pinf = 9**9**9;
my $nan = $pinf - $pinf;
my $minf = -$pinf;

my $inan = 0|$nan;
my $ipinf = 0|$pinf;
my $iminf = 0|$minf;

printf "%x|%x|%x\n", $inan, $ipinf, $iminf;

Est-ce un sentiment?

Les résultats sont présentés dans le tableau ci-dessous:

Système de traitement NaN +INF -INF
perl v5.18.2 0 ffffffffffffffff 8000000000000000

La valeur est difficile à comprendre.

ʻInt x` n'est pas intéressant car il peut rester nan.

Swift

J'ai écrit Swift pour la première fois de ma vie, mais je ne pouvais pas bien l'écrire et j'ai été vaincu.

print(
    Int(Double.nan), "|",
    Int(Double.infinity), "|",
    Int(-Double.infinity), "|")

Quand tu cours

Fatal error: Double value cannot be converted to Int because it is either infinite or NaN

Sera. (Je n'ai mis que la première ligne, mais en réalité j'obtiens un message d'erreur de 10 lignes ou plus)

Je voulais attraper cette erreur et afficher le type d'erreur, mais je ne savais pas comment l'attraper et la perdre. Rapide difficile.

Bref. Dans le cas de Swift, si vous essayez de changer NaN ou INF en un entier avec ʻInt () , vous obtiendrez" Erreur fatale`". C'est horrible.

En outre. Swift fonctionne avec xcrun swift, et la version qui sort avec xcrun swift --version est

Apple Swift version 4.2.1 (swiftlang-1000.11.42 clang-1000.11.45.1)
Target: x86_64-apple-darwin18.2.0

Il est devenu.

fortran

S'agit-il de fortran2003? Je l'ai écrit sans le savoir bien. Tel

fortran


function div(a,b)
  real a, b
  div = a/b
end function

program main
  real :: nan
  real :: pinf
  real :: minf
  nan = div(0.0,0.0)
  pinf = div(1.0,0.0)
  minf = -pinf
  print *, int(nan), "|", int(pinf), "|", int(minf)
end

Sentiment. Allumettes? L'environnement est GNU Fortran (Homebrew GCC 8.2.0) 8.2.0.

Le résultat est

Système de traitement NaN +INF -INF
gfortran8.2 -2147483648 -2147483648 -2147483648

Et la même chose que le langage C. Je me demande si cela dépend du processeur.

Dart

J'ai écrit Dart pour la première fois de ma vie.

dart


import 'dart:io';

toIntStr( n ){
  try{
    return n.toInt().toString();
  }
  catch(e){
    return  "exception";
  }
}

void main() {
  stdout.write(toIntStr(double.nan));
  stdout.write("|");
  stdout.write(toIntStr(double.infinity));
  stdout.write("|");
  stdout.write(toIntStr(double.negativeInfinity));
  print("|");
}

Comme ça. Le résultat est

Système de traitement NaN +INF -INF
Dart VM version: 2.1.0 exception exception exception

L'exception est 「Unsupported operation: Infinity or NaN toInt」 Le contenu.

Haskell

Le code source est comme ça

nan = 0.0/0.0
pinf = 1.0/0.0
minf = -pinf
toint :: (Double->Int)->Double->Int
toint f x = f(x)

table t f = 
  "|"++t++"|"++
  (show $ toint f nan)++"|"++
  (show $ toint f pinf)++"|"++
  (show $ toint f minf)++"|"

main = do
  putStrLn $ table "round" round
  putStrLn $ table "truncate" truncate
  putStrLn $ table "ceiling" ceiling
  putStrLn $ table "floor" floor

Sentiment.

Le système de traitement est «The Glorious Glasgow Haskell Compilation System, version 8.4.4».

Quand tu cours

une fonction NaN +INF -INF
round 0 0 0
truncate 0 0 0
ceiling 0 0 0
floor 0 0 0

Et il devient nul de manière inattendue. Il n'y a pas d'exceptions.

Résumé

J'en ai fait une table.

Système de traitement veux dire NaN +INF -INF
C99 on amd64 jeter -2147483648 -2147483648 -2147483648
ruby 2.5 .to_i exception exception exception
python int() exception exception exception
python de numpy.astype -2147483648 -2147483648 -2147483648
go on amd64 int32() -2147483648 -2147483648 -2147483648
C# (int) -2147483648 -2147483648 -2147483648
Java1.8 (int) 0 2147483647 -2147483648
Groovy(JVM1.8) (int) 0 2147483647 -2147483648
JavaScript(nodejs) or op. 0 0 0
JavaScript(nodejs) Uint16Array 0 0 0
Rust on amd64 as i32 -2147483648 -2147483648 -2147483648
PHP 7.1.19 (int), intval() 0 0 0
perl5.18 or op. 0 ffffffffffffffff 8000000000000000
Swift4.2.1 Int() Fatal error Fatal error Fatal error
gfortran8.2 int() -2147483648 -2147483648 -2147483648
Dart2.1 .toInt() exception exception exception
Haskell(GHC8.4) rond etc. 0 0 0
résultat Système de traitement
-Devient 2147483648 C99, numpy, go ,Rust, gfortran (Tout amd64)
Soyez une exception ruby, python, Dart
Devenir 0 JavaScript, PHP7, Haskell
Mourir avec une erreur fatale Swift4
Autre Java, Groovy, Perl5

Je me demande si tel est le cas.

bien

Eh bien, j'ai essayé diverses choses.

Recommended Posts

J'ai essayé de savoir ce qui se passerait si je convertissais NaN ou INF en int
J'ai essayé de savoir si ReDoS est possible avec Python
J'ai essayé de savoir ce que je pouvais faire car le tranchage est pratique
J'ai essayé de savoir si m est inclus dans ce qu'on appelle le type de plage ou une plage telle que n..m et plage (n, m)
J'ai essayé de découvrir les grandes lignes de Big Gorilla
les débutants en python ont essayé de le découvrir
Je me demandais ce qui se passerait si je passais le générateur à la fonction intégrée Python enumerate (), alors j'ai expérimenté.
Que faire si PDO n'est pas trouvé dans Laravel ou CakePHP
J'ai étudié comment rationaliser le flux de travail avec Excel x Python ②
J'ai étudié comment rationaliser le flux de travail avec Excel x Python ④
J'ai essayé de savoir comment rationaliser le flux de travail avec Excel x Python ⑤
AtCoder Beginner Contest 177 Problème C J'ai essayé de découvrir pourquoi c'était faux
[Test de décorrélation] J'ai essayé d'éteindre la ligne de démarcation avec ou sans rejet
J'ai étudié comment rationaliser le flux de travail avec Excel x Python ③
J'ai essayé de trouver la classe alternative avec tensorflow