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?
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.
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.
Eh bien, j'ai essayé diverses choses.
Recommended Posts