Various processing systems can be used to see what happens when a floating-point non-number or infinity is converted to an int.
The environment is mainly macOS Mojave 10.14.2. Only cl.exe (C language) and C # are windows 10 (64bit). Both CPUs are x64.
I'm curious about what happens with ARM, but I don't have the environment at hand. Would you like to write an article?
The source code is like this
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;
}
Feeling.
Processing system | 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 |
I think it is "undefined behavior" in C language.
For clang and gcc, it's a 2015 MacBookPro, so x64. cl.exe (Visual Studio) is also x64. I didn't build on x86.
By the way, div
is a function becausedouble nan = 0.0 / 0.0;
is a compile error in cl.exe. I get an error at compile time but nan at run time.
ruby
The source code is like this
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("|")
Feeling.
Processing system | 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" |
Surprisingly an exception.
In jruby, of course, with ruby, the result will be different from java (described later). Is it natural?
python
The source code is like this
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"))
Feeling.
Processing system | means | 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 when made with int (). Well that's right. With numpy, there is no time to throw exceptions. It became the same as C language.
go
The source code is like this
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))
}
Feeling.
Processing system | NaN | +INF | -INF |
---|---|---|---|
go1.11.2 darwin/amd64 | -2147483648 | -2147483648 | -2147483648 |
Making it panic is overkill, and there are no exceptions, so there is no choice but to make it a strange value like C language.
According to Go Programming Language Specification
For all non-constant conversions that contain floating point values or complex numbers, if the resulting type cannot represent a value, the conversion itself succeeds, but the resulting value is implementation-dependent.
So it seems to be implementation-dependent.
C#
The source code is like this
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 );
}
}
}
Feeling.
Processing system | NaN | +INF | -INF |
---|---|---|---|
csc 2.10.0.0 | -2147483648 | -2147483648 | -2147483648 |
It has the same value as clang and gcc without exception.
By the way
(decimal)double.NaN
If you do, a slightly inappropriate message
"System.OverflowException: Decimal type value is too large or too small.
"
Is an exception.
Java
The source code is like this
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);
}
}
Feeling.
I wrote " public static void main
"after a long time.
Processing system | NaN | +INF | -INF |
---|---|---|---|
java version "1.8.0_60" | 0 | 2147483647 | -2147483648 |
Java is no exception. It will be different from clang, gcc and go.
By the way, new BigDecimal (Double.NaN);
is an exception of " java.lang.NumberFormatException: Infinite or NaN
".
groovy
The source code is like this
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);
Feeling.
Processing system | NaN | +INF | -INF |
---|---|---|---|
Groovy Version: 2.5.4 JVM: 1.8.0_60 | 0 | 2147483647 | -2147483648 |
It still gives the same result as 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("|"))
The processing system is v11.3.0 of node.js.
means | NaN | +INF | -INF |
---|---|---|---|
or op. | 0 | 0 | 0 |
and op. | 0 | 0 | 0 |
u16a | 0 | 0 | 0 |
i16a | 0 | 0 | 0 |
If you try to make it a 32-bit integer, or if you plunge into an integer type with a limited number of bits, it will be zero.
Doing something like math.floor (x)
will result in NaN
or ʻInfinity`, which is not interesting.
Rust
The source code is like this
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);
}
Feeling.
Surprisingly no exception. Result is
Processing system | NaN | +INF | -INF |
---|---|---|---|
rustc 1.30.1 | -2147483648 | -2147483648 | -2147483648 |
However, according to Cast between types
** Note: This cast causes undefined behavior if the rounded value cannot currently be handled by the destination integer type. ** This includes Inf and NaN. This is a bug and will be fixed.
It seems that it will be ** corrected **.
PHP
The source code is like this
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" );
?>
I wonder if it feels good. I do not know.
The result is surprising
Processing system | means | NaN | +INF | -INF |
---|---|---|---|---|
PHP 7.1.19 | (int) | 0 | 0 | 0 |
PHP 7.1.19 | intval() | 0 | 0 | 0 |
And all become zero.
perl
The source code is like this
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;
Is it a feeling?
The results are shown in the table below:
Processing system | NaN | +INF | -INF |
---|---|---|---|
perl v5.18.2 | 0 | ffffffffffffffff | 8000000000000000 |
The value is difficult to understand.
ʻInt x` is not interesting because it may remain nan.
Swift
I wrote Swift for the first time in my life, but I couldn't write it well and was defeated.
print(
Int(Double.nan), "|",
Int(Double.infinity), "|",
Int(-Double.infinity), "|")
When executed
Fatal error: Double value cannot be converted to Int because it is either infinite or NaN
Will be. (I put out only the first line, but in reality I get an error message of 10 or more lines)
I wanted to catch this error and output the type of error, but I didn't know how to catch it and lost. Swift difficult.
Anyways. In the case of Swift, if you try to make NaN or INF an integer with ʻInt () , it seems to be"
Fatal error`". That's horrible.
In addition.
Swift is running with xcrun swift
, and the version that comes out with xcrun swift --version
is
Apple Swift version 4.2.1 (swiftlang-1000.11.42 clang-1000.11.45.1)
Target: x86_64-apple-darwin18.2.0
It has become.
fortran
Is it about fortran2003? I wrote it without knowing it well. Such
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
Feeling. Matches? The environment is GNU Fortran (Homebrew GCC 8.2.0) 8.2.0.
Result is
Processing system | NaN | +INF | -INF |
---|---|---|---|
gfortran8.2 | -2147483648 | -2147483648 | -2147483648 |
And the same as C language. I wonder if it depends on the CPU.
Dart
I wrote Dart for the first time in my life.
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("|");
}
Like this. Result is
Processing system | NaN | +INF | -INF |
---|---|---|---|
Dart VM version: 2.1.0 | exception | exception | exception |
The exception is
「Unsupported operation: Infinity or NaN toInt
」
The content.
Haskell
The source code is like this
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
Feeling.
The processing system is The Glorious Glasgow Haskell Compilation System, version 8.4.4
.
When executed
function | NaN | +INF | -INF |
---|---|---|---|
round | 0 | 0 | 0 |
truncate | 0 | 0 | 0 |
ceiling | 0 | 0 | 0 |
floor | 0 | 0 | 0 |
And it becomes zero unexpectedly. There are no exceptions.
I made it a table.
Processing system | means | NaN | +INF | -INF |
---|---|---|---|---|
C99 on amd64 | cast | -2147483648 | -2147483648 | -2147483648 |
ruby 2.5 | .to_i | exception | exception | exception |
python | int() | exception | exception | exception |
python | of 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) | round etc. | 0 | 0 | 0 |
result | Processing system |
---|---|
-Becomes 2147483648 | C99, numpy, go ,Rust, gfortran (All amd64) |
Be an exception | ruby, python, Dart |
Become 0 | JavaScript, PHP7, Haskell |
Die with a Fatal error | Swift4 |
Other | Java, Groovy, Perl5 |
I wonder if that is the case.
Well, I tried various things.
Recommended Posts