[PYTHON] Ich versuchte herauszufinden, was passieren würde, wenn ich NaN oder INF in int konvertieren würde

Was passiert, wenn Sie in verschiedenen Verarbeitungssystemen eine Gleitkommazahl ohne Zahl oder unendlich in int konvertieren?

Die Umgebung ist hauptsächlich macOS Mojave 10.14.2. Nur cl.exe (Sprache C) und C # sind Windows 10 (64 Bit). Beide haben eine x64-CPU.

Ich bin gespannt, was mit ARM passiert, aber ich habe keine Umgebung zur Hand. Möchten Sie einen Artikel schreiben?

C Sprache

Der Quellcode ist so

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;
}

Gefühl.

Verarbeitungssystem 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

Ich denke, es ist "undefiniertes Verhalten" in C-Sprache.

Für Clang und GCC ist es ein 2015 MacBookPro, also x64. cl.exe (Visual Studio) ist ebenfalls x64. Hat nicht auf x86 aufgebaut.

Übrigens ist div eine Funktion, weil double nan = 0.0 / 0.0; cl.exe ist und einen Kompilierungsfehler verursacht. Ich erhalte einen Fehler beim Kompilieren, aber nan zur Laufzeit.

ruby

Der Quellcode ist so

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("|")

Gefühl.

Verarbeitungssystem 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"

Überraschenderweise eine Ausnahme.

In jruby unterscheidet sich das Ergebnis natürlich mit rubin von java (später beschrieben). Ist es natürlich?

python

Der Quellcode ist so

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"))

Gefühl.

Verarbeitungssystem meint 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

Ausnahme bei int (). Nun, das stimmt. Mit numpy ist keine Zeit, eine Ausnahme auszulösen. Es wurde das gleiche wie C-Sprache.

go

Der Quellcode ist so

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))
}

Gefühl.

Verarbeitungssystem NaN +INF -INF
go1.11.2 darwin/amd64 -2147483648 -2147483648 -2147483648

Es in Panik zu versetzen ist übertrieben, und es gibt keine Ausnahmen. Es bleibt also nichts anderes übrig, als es zu einem seltsamen Wert wie in der C-Sprache zu machen.

Gemäß Go Programming Language Specification

Wenn bei allen nicht konstanten Konvertierungen, die Gleitkommawerte oder komplexe Zahlen enthalten, der resultierende Typ keinen Wert darstellen kann, ist die Konvertierung selbst erfolgreich, der resultierende Wert ist jedoch implementierungsabhängig.

Es scheint also implementierungsabhängig zu sein.

C#

Der Quellcode ist so

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 );
        }
    }
}

Gefühl.

Verarbeitungssystem NaN +INF -INF
csc 2.10.0.0 -2147483648 -2147483648 -2147483648

Es ist ausnahmslos der gleiche Wert wie clang und gcc.

Apropos (decimal)double.NaN Wenn Sie dies tun, eine etwas unangemessene Nachricht "System.OverflowException: Wert vom Typ Dezimal ist zu groß oder zu klein." Ist eine Ausnahme.

Java

Der Quellcode ist so

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);
  }
}

Gefühl.

Ich habe nach langer Zeit " public static void main "geschrieben.

Verarbeitungssystem NaN +INF -INF
java version "1.8.0_60" 0 2147483647 -2147483648

Java ist keine Ausnahme. Der Wert unterscheidet sich von clang, gcc und go.

Übrigens ist "new BigDecimal (Double.NaN);" eine Ausnahme von "java.lang.NumberFormatException: Infinite or NaN".

groovy

Der Quellcode ist so

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);

Gefühl.

Verarbeitungssystem NaN +INF -INF
Groovy Version: 2.5.4 JVM: 1.8.0_60 0 2147483647 -2147483648

Es gibt immer noch das gleiche Ergebnis wie 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("|"))

Das Verarbeitungssystem ist v11.3.0 von node.js.

meint NaN +INF -INF
or op. 0 0 0
and op. 0 0 0
u16a 0 0 0
i16a 0 0 0

Wenn Sie versuchen, eine 32-Bit-Ganzzahl daraus zu machen, oder wenn Sie in einen Ganzzahltyp mit einer begrenzten Anzahl von Bits eintauchen, ist dieser Wert Null. Wenn Sie so etwas wie "math.floor (x)" machen, ist es "NaN" oder "Infinity", also ist es nicht interessant.

Rust

Der Quellcode ist so

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);
}

Gefühl.

Überraschenderweise keine Ausnahme. Ergebnis ist

Verarbeitungssystem NaN +INF -INF
rustc 1.30.1 -2147483648 -2147483648 -2147483648

Laut Besetzung zwischen Typen

** Hinweis: Derzeit verursacht diese Umwandlung ein undefiniertes Verhalten, wenn der gerundete Wert nicht vom Ziel-Integer-Typ verarbeitet werden kann. ** Dies beinhaltet Inf und NaN. Dies ist ein Fehler und wird behoben.

Es scheint, dass es ** korrigiert ** wird.

PHP

Der Quellcode ist so

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" );
?>

Ich frage mich, ob es sich gut anfühlt. Ich weiß es nicht.

Das Ergebnis ist überraschend

Verarbeitungssystem meint NaN +INF -INF
PHP 7.1.19 (int) 0 0 0
PHP 7.1.19 intval() 0 0 0

Und alle werden Null.

perl

Der Quellcode ist so

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;

Ist es ein Gefühl?

Die Ergebnisse sind in der folgenden Tabelle aufgeführt:

Verarbeitungssystem NaN +INF -INF
perl v5.18.2 0 ffffffffffffffff 8000000000000000

Der Wert ist schwer zu verstehen.

Wenn es "int x" ist, bleibt es nan, also ist es nicht interessant.

Swift

Ich habe Swift zum ersten Mal in meinem Leben geschrieben, aber ich konnte es nicht gut schreiben und wurde besiegt.

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

Wenn du rennst

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

Wird sein. (Ich habe nur die erste Zeile ausgegeben, aber in Wirklichkeit wird eine Fehlermeldung von 10 oder mehr Zeilen angezeigt.)

Ich wollte diesen Fehler abfangen und die Art des Fehlers ausgeben, wusste aber nicht, wie ich ihn abfangen sollte und verlor. Schnell schwierig.

Sowieso. Wenn Sie im Fall von Swift versuchen, NaN oder INF in eine Ganzzahl mit "Int ()" zu ändern, erhalten Sie "Schwerwiegender Fehler". Das ist schrecklich.

Und dazu. Swift läuft mit "xcrun swift" und die Version, die mit "xcrun swift --version" herauskommt, ist

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

Es ist geworden.

fortran

Geht es um fortran2003? Ich habe es geschrieben, ohne es gut zu wissen. Eine solche

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

Gefühl. Streichhölzer? Die Umgebung ist GNU Fortran (Homebrew GCC 8.2.0) 8.2.0.

Ergebnis ist

Verarbeitungssystem NaN +INF -INF
gfortran8.2 -2147483648 -2147483648 -2147483648

Und das gleiche wie C-Sprache. Ich frage mich, ob es von der CPU abhängt.

Dart

Ich habe Dart zum ersten Mal in meinem Leben geschrieben.

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("|");
}

So was. Ergebnis ist

Verarbeitungssystem NaN +INF -INF
Dart VM version: 2.1.0 exception exception exception

Die Ausnahme ist 「Unsupported operation: Infinity or NaN toInt」 Der Inhalt.

Haskell

Der Quellcode ist so

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

Gefühl.

Das Verarbeitungssystem ist "The Glorious Glasgow Haskell Compilation System, Version 8.4.4".

Wenn du rennst

Funktion NaN +INF -INF
round 0 0 0
truncate 0 0 0
ceiling 0 0 0
floor 0 0 0

Und es wird unerwartet Null. Es gibt keine Ausnahmen.

Zusammenfassung

Ich habe daraus einen Tisch gemacht.

Verarbeitungssystem meint NaN +INF -INF
C99 on amd64 Besetzung -2147483648 -2147483648 -2147483648
ruby 2.5 .to_i Ausnahme Ausnahme Ausnahme
python int() Ausnahme Ausnahme Ausnahme
python von 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() Ausnahme Ausnahme Ausnahme
Haskell(GHC8.4) rund usw. 0 0 0
Ergebnis Verarbeitungssystem
-Wird 2147483648 C99, numpy, go ,Rust, gfortran (Alles amd64)
Sei eine Ausnahme ruby, python, Dart
Werden Sie 0 JavaScript, PHP7, Haskell
Stirb mit schwerwiegendem Fehler Swift4
Andere Java, Groovy, Perl5

Ich frage mich, ob das der Fall ist.

Gut

Nun, ich habe verschiedene Dinge ausprobiert.

Recommended Posts

Ich versuchte herauszufinden, was passieren würde, wenn ich NaN oder INF in int konvertieren würde
Ich habe versucht herauszufinden, ob ReDoS mit Python möglich ist
Ich habe versucht herauszufinden, was ich tun kann, weil das Schneiden bequem ist
Ich habe versucht herauszufinden, ob m in dem sogenannten Bereichstyp oder Bereich wie n..m und Bereich (n, m) enthalten ist.
Ich habe versucht, die Umrisse von Big Gorilla herauszufinden
Python-Anfänger versuchten es herauszufinden
Ich habe mich gefragt, was passieren würde, wenn ich den Generator an die in Python integrierte Funktion enumerate () übergeben würde, also habe ich experimentiert.
Was tun, wenn PDO nicht in Laravel oder CakePHP gefunden wird?
Ich habe untersucht, wie der Arbeitsablauf mit Excel x Python optimiert werden kann
Ich habe untersucht, wie der Arbeitsablauf mit Excel x Python ④ optimiert werden kann
Ich habe versucht herauszufinden, wie der Arbeitsablauf mit Excel x Python optimiert werden kann
AtCoder Beginner Contest 177 Problem C Ich habe versucht herauszufinden, warum es falsch war
[Nichtkorrelationstest] Ich habe versucht, die Grenzlinie mit oder ohne Ablehnung zu löschen
Ich habe untersucht, wie der Arbeitsablauf mit Excel x Python optimiert werden kann
Ich habe versucht, die alternative Klasse mit Tensorflow zu finden