为什么C#允许:
1.0 / 0 // Infinity
Run Code Online (Sandbox Code Playgroud)
并且不允许:
1 / 0 // Division by constant zero [Compile time error]
Run Code Online (Sandbox Code Playgroud)
在数学上,积分和浮点数除以零之间是否有任何差异?
考虑
#include <iostream>
int main()
{
double a = 1.0 / 0;
double b = -1.0 / 0;
double c = 0.0 / 0;
std::cout << a << b << c; // to stop compilers from optimising out the code.
}
Run Code Online (Sandbox Code Playgroud)
我一直认为这a将是+ Inf,b将是-Inf,并且c将是NaN.但我也听到传言说严格来说浮点除零的行为是未定义的,因此上面的代码不能被认为是可移植的C++.(理论上,这会消除我的百万行加上代码堆栈的完整性.糟糕.)
谁是对的?
注意我对实现定义感到满意,但我在谈论吃猫,在这里恶魔打喷嚏的未定义行为.
c++ floating-point divide-by-zero undefined-behavior language-lawyer
只是把一个简单的测试扔到一起,不是出于任何特殊原因,除了我想尝试对我的所有方法进行测试,即使这个非常简单,或者我认为.
[TestMethod]
public void Test_GetToolRating()
{
var rating = GetToolRating(45.5, 0);
Assert.IsNotNull(rating);
}
private static ToolRating GetToolRating(double total, int numberOf)
{
var ratingNumber = 0.0;
try
{
var tot = total / numberOf;
ratingNumber = Math.Round(tot, 2);
}
catch (Exception ex)
{
var errorMessage = ex.Message;
//log error here
//var logger = new Logger();
//logger.Log(errorMessage);
}
return GetToolRatingLevel(ratingNumber);
}
Run Code Online (Sandbox Code Playgroud)
正如您在测试方法中看到的那样,我将其除以零.问题是,它不会产生错误.请参阅下面的错误窗口显示.
而不是错误,它给出无穷大的价值?我错过了什么?所以我用谷歌搜索,发现双倍除以零不要产生错误,他们要么给出无效或无穷大.那么问题就是,如何测试Infinity的返回值?
如果我在常量表达式中除以零,我的玩具编译器会崩溃:
int x = 1 / 0;
Run Code Online (Sandbox Code Playgroud)
C和/或C++标准是否允许这种行为?
c c++ compile-time-constant divide-by-zero constant-expression
请考虑以下代码和评论:
Console.WriteLine(1 / 0); // will not compile, error: Division by constant zero
int i = 0;
Console.WriteLine(1 / i); // compiles, runs, throws: DivideByZeroException
double d = 0;
Console.WriteLine(1 / d); // compiles, runs, results in: Infinity
Run Code Online (Sandbox Code Playgroud)
我可以理解编译器在运行时主动检查除零常量和DivideByZeroException但是:
为什么在"除零"中使用双精度返回Infinity而不是抛出异常?这是设计还是错误?
只是为了踢,我也在VB.NET中做到了这一点,结果是"更一致":
dim d as double = 0.0
Console.WriteLine(1 / d) ' compiles, runs, results in: Infinity
dim i as Integer = 0
Console.WriteLine(1 / i) ' compiles, runs, results in: Infinity
Console.WriteLine(1 / 0) ' compiles, runs, results in: Infinity …Run Code Online (Sandbox Code Playgroud) 以下在我的Eclipse中编译得很好:
final int j = 1/0;
// compiles fine!!!
// throws ArithmeticException: / by zero at run-time
Run Code Online (Sandbox Code Playgroud)
Java的防止了许多"哑代码"从甚至在首位编译(如"Five" instanceof Number不编译),所以其实这甚至没有产生尽可能多的警告是非常令我感到诧异.当您考虑允许在编译时优化常量表达式这一事实时,阴谋会加深:
public class Div0 {
public static void main(String[] args) {
final int i = 2+3;
final int j = 1/0;
final int k = 9/2;
}
}
Run Code Online (Sandbox Code Playgroud)
在Eclipse中编译,上面的代码片段生成以下字节码(javap -c Div0)
Compiled from "Div0.java"
public class Div0 extends java.lang.Object{
public Div0();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: …Run Code Online (Sandbox Code Playgroud) 我有统计问题的功能:
import numpy as np
from scipy.special import gamma as Gamma
def Foo(xdata):
...
return x1 * (
( #R is a numpy vector
( ((R - x2)/beta) ** (x3 -1) ) *
( np.exp( - ((R - x2) / x4) ) ) /
( x4 * Gamma(x3))
).real
)
Run Code Online (Sandbox Code Playgroud)
有时我会从shell获得以下警告:
RuntimeWarning: divide by zero encountered in...
Run Code Online (Sandbox Code Playgroud)
我使用numpy isinf函数来纠正其他文件中函数的结果,所以我不需要这个警告.
有没有办法忽略这条消息?换句话说,我不希望shell打印此消息.
我不想禁用所有python警告,只是这个.
我有一个必须动态创建的大型数学表达式.例如,一旦我解析了"某事",结果将是一个字符串,如:"$foo+$bar/$baz";.
所以,为了计算该表达式的结果,我正在使用eval函数......这样的事情:
eval("\$result = $expresion;");
echo "The result is: $result";
Run Code Online (Sandbox Code Playgroud)
这里的问题是,有时我会得到错误,表示存在除零的错误,而且我不知道如何捕获该异常.我尝试过这样的事情:
eval("try{\$result = $expresion;}catch(Exception \$e){\$result = 0;}");
echo "The result is: $result";
Run Code Online (Sandbox Code Playgroud)
要么:
try{
eval("\$result = $expresion;");
}
catch(Exception $e){
$result = 0;
}
echo "The result is: $result";
Run Code Online (Sandbox Code Playgroud)
但它不起作用.那么,如果存在除零值,我怎么能避免我的应用程序崩溃?
编辑:
首先,我想澄清一下:表达式是动态构建的,所以如果分母为零,我不能只评估它.那么......关于Mark Baker的评论,让我举个例子.我的解析器可以构建这样的东西:
"$foo + $bar * ( $baz / ( $foz - $bak ) )"
Run Code Online (Sandbox Code Playgroud)
解析器逐步构建字符串而不用担心变量的值...所以在这种情况下如果$foz == $bak实际上除以零:$baz / ( 0 ).
另一方面,正如皮特建议的那样,我尝试过:
<?php
$a = 5;
$b = 0;
if(@eval(" …Run Code Online (Sandbox Code Playgroud) 我有一个需要两个输入的I2C设备:分母和分子.两者都写入单独的地址,因此不进行实际的计算(numerator/denominator).这样做的问题是在I2C器件上可能会出现除零,因此需要检查除零误差.理想情况下,如果划分由java代码完成,则会发生完全相同的事情.
目前,我已经提供了一个未使用的变量进行划分,但我担心它会被优化掉:
public void setKp(int numerator, int divisor)
{
int zeroCheck = numerator / divisor;
//... doesn't use zeroCheck
}
Run Code Online (Sandbox Code Playgroud)
当然有更好的方法!
关于除零,标准说:
C99 6.5.5p5 - /运算符的结果是第一个操作数除以第二个操作数的商; %运算符的结果是余数.在这两个操作中,如果第二个操作数的值为零,则行为未定义.
C++ 03 5.6.4 - 二进制/运算符产生商,二进制%运算符从第一个表达式除以第二个表达式得到余数.如果/或%的第二个操作数为零,则行为未定义.
如果我们将上述段落视为面值,答案显然是两种语言的未定义行为.但是,如果我们进一步了解C99标准,我们会看到以下段落似乎是矛盾的(1):
C99 7.12p4 - 宏INFINITY扩展为float类型的常量表达式,表示正无穷大或无符号无穷大(如果可用);
标准是否有某种黄金法则,其中未定义的行为不能被(可能)矛盾的陈述所取代?除此之外,我认为如果你的实现定义了INFINITY宏,那么将零除法定义为这样是不合理的.但是,如果您的实现没有定义这样的宏,则行为是Undefined.
我很好奇这两种语言在这个问题上的共识是什么(如果有的话).如果我们谈论整数除法int i = 1 / 0与浮点除法,答案会改变float i = 1.0 / 0.0吗?
注意(1) C++ 03标准讨论了<cmath>包含INFINITY宏的库.