[RUBY] I tried to find out what would happen if I converted NaN or INF to int

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?

C language

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.

Summary

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

Well, I tried various things.

Recommended Posts

I tried to find out what would happen if I converted NaN or INF to int
I tried to find out if ReDoS is possible with Python
I tried to find out what I can do because slicing is convenient
I tried to find out if m is included in what is called a range type or range such as n..m and range (n, m).
I tried to find out the outline about Big Gorilla
python beginners tried to find out
I was wondering what would happen if I passed the generator to Python's built-in function enumerate (), so I experimented.
What to do if you can't find PDO in Laravel or CakePHP
I tried to find out how to streamline the work flow with Excel x Python ②
I tried to find out how to streamline the work flow with Excel x Python ④
I tried to find out how to streamline the work flow with Excel x Python ⑤
AtCoder Beginner Contest 177 Problem C I tried to find out why it was wrong
[Uncorrelated test] I tried to put out the boundary line with or without rejection
I tried to find out how to streamline the work flow with Excel x Python ③
I tried to find an alternating series with tensorflow