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?
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 |
** 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.
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.
Nun, ich habe verschiedene Dinge ausprobiert.
Recommended Posts