当浮点数除以零时,我可以强制java抛出错误吗?
我编写了一个模拟器,它有一些碰撞检测代码,并在检测到碰撞时对每个对象进行大量数学计算。
如果这两个对象位于完全相同的位置或在一些罕见的其他情况下,我会得到 NaN (不是数字)作为它们沿线某处的位置,我想知道在哪里。 通常,如果我对整数执行这些操作,程序会崩溃,但因为 + 和 - 无穷大是浮点规范的一部分,所以这是允许的。
因此,在这条线上的某个地方,我取负数的平方根或除以零。
无论如何,我是否可以让我的程序在导致此问题的操作上自动崩溃,以便我可以缩小范围?
I wrote a simulator that has some collision detection code and does a good bit of math on each object when it detects collisions.
If these two objects are at the exact same location or in some rare other cases, I'm getting NaN (not a number) as their location somewhere along the line and I'd like to know where. Normally, the program would crash if I did these operations on integers but because + and - infinity are part of the floating point spec, it is allowed.
So, somewhere along the line I'm taking a square root of a negative number or dividing by zero.
Is there anyway I can make my program automatically crash on the operations that cause this so I can narrow it down some?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我认为您不能引发除以零的异常,除非您在除法之前测试数字并自己引发异常。
浮点数的问题在于,标准要求结果为 NaN(非数字)浮点数。 据我所知,所有 JVM 和编译器都遵循这方面的标准。
I don't think you can raise a divide by zero exception unless you test the numbers before the division and raise the exception yourself.
The problem with floats is, that the standard requires that the result gets a NaN (Not a Number) float. And all JVMs and compilers that I am aware off follow the standard in this respect.
您可以处理二进制类,查找 fdiv 操作,插入除以零的检查。
Java:
javap 输出:
替换代码除以零时抛出 ArithemticException:
此处理可以使用字节码操作 API 来完成,例如 ASM。 这并不是一件小事,但也不是火箭科学。
如果您想要的只是监视(而不是更改代码的操作),那么更好的方法可能是使用调试器。 我不确定什么调试器允许您编写表达式来捕获您要查找的内容,但编写自己的调试器并不困难。 Sun JDK 提供了 JPDA 和示例显示如何使用它的代码(解压缩 jdk/demo/jpda/examples.jar)。
连接到本地主机上的套接字的示例代码:
You could process your binary classes looking for fdiv operations, inserting a check for divide by zero.
Java:
javap output:
Replacement code that throws a ArithemticException for divide-by-zero:
This processing can be done using bytecode manipulation APIs like ASM. This isn't really trivial, but it isn't rocket science either.
If all you want is monitoring (rather than changing the operation of the code), then a better approach might be to use a debugger. I'm not sure what debuggers would allow you to write an expression to catch what you're looking for, but it isn't difficult to write your own debugger. The Sun JDK provides the JPDA and sample code showing how to use it (unzip jdk/demo/jpda/examples.jar).
Sample code that attaches to a socket on localhost:
扩展 McDowell 处理二进制类的建议,我编写了一些代码,这些代码已成功用于相对较大的代码库,我想分享: https://bitbucket.org/Oddwarg/java-sigfpe-emulator/
我使用 Krakatau 来反汇编和重新组装类文件。 必须将包含公共静态辅助方法
float notZero(float f)
和double notZero(double f)
的小型 Java 类作为流程的一部分添加到应用程序中。原则上,对字节码汇编的修改非常简单:当遇到
fdiv
或ddiv
指令时,调用相应的notZero
首先插入函数。在此示例中,L29 和 L30 之间的行是由程序插入的。
notZero
调用使用操作数堆栈的顶部作为其参数,即除数。 如果除数不为零,则将其返回,并将其放回到操作数堆栈的顶部。 如果除数为零,则会抛出 ArithmeticException。调用方法并确保操作数堆栈保持相同可以避免与堆栈映射帧和操作数堆栈溢出相关的大多数问题,但我确实必须确保 .stack same 类型帧之间的距离保持不变低于阈值。 它们根据需要重复。
我希望这对某人有用。 我自己花了足够多的时间手动搜索浮点除以零。
Expanding on McDowell's proposal to process the binary classes, I wrote some code that I've used with success for a relatively large codebase, and I'd like to share: https://bitbucket.org/Oddwarg/java-sigfpe-emulator/
I used Krakatau to disassemble and reassemble class files. A small Java class containing the public, static helper methods
float notZero(float f)
anddouble notZero(double f)
must be added to the application as a part of the process.The modification to the bytecode assembly is, in principle, very simple: When an
fdiv
orddiv
instruction is encountered, a call to the appropriatenotZero
function is inserted first.In this example, the line between L29 and L30 was inserted by the program.
The
notZero
call consumes the top of the operand stack as its argument, which is the divisor. If the divisor is not zero, then it is returned, putting it back on top of the operand stack. If the divisor is zero, then anArithmeticException
is thrown instead.Calling a method and making sure the operand stack remains the same avoids most of the problems related to Stack Map Frames and operand stack overflow, but I did have to ensure the distance between
.stack same
-type frames remains below a threshold. They are repeated on demand.I hope this will be useful to someone. I've spent more than enough time manually searching for floating point divisions by zero myself.
我不知道你可以在虚拟机中设置什么来实现这一点。
根据你的代码的结构,我会在我的方法中添加以下类型的检查(我只是出于习惯而一直这样做 - 虽然非常有用):
如果你需要浮点数的精确表示,你需要查看java.math.BigDecimal。
I am not aware of anything you can set in the VM to make that happen.
Depending on how your code is structured I would add the following sort of checks to my methods (I just do this all the time out of habit mostly - very useful though):
If you need exact representations of floating point numbers you need to look at java.math.BigDecimal.
我可以建议您使用 AOP(例如 AspectJ)来捕获异常并为您提供额外的运行时信息。
两个可能相关的用例:
取决于如何当你部署你的软件时,你可以使用不同的AOP编织策略(运行时、加载时等)。
I can advise you to use AOP (e.g. AspectJ) for catching exceptions and providing you additional run-time information.
Two use cases that can be relevant:
Depends on how you deploy your software, you can use different AOP weaving strategies (run-time, load-time etc.).