2

いくつかの衝突検出コードを持ち、衝突を検出するときに各オブジェクトに対して適切な計算を行うシミュレーターを作成しました。

これらの2つのオブジェクトがまったく同じ場所にある場合、またはまれに他の場合には、線に沿った場所としてNaN(数値ではない)を取得しているので、どこにあるか知りたいです。通常、整数に対してこれらの操作を行うとプログラムがクラッシュしますが、+と-の無限大は浮動小数点仕様の一部であるため、許可されています。

したがって、線のどこかで、負の数の平方根をとるか、ゼロで除算しています。

とにかく、これを引き起こす操作でプログラムを自動的にクラッシュさせて、いくつかを絞り込むことができますか?

4

5 に答える 5

9

除算の前に数値をテストして自分で例外を発生させない限り、ゼロ除算の例外を発生させることはできないと思います。

floatの問題は、標準では結果がNaN(数値ではない)floatを取得することを要求していることです。そして、私が知っているすべてのJVMとコンパイラーは、この点で標準に準拠しています。

于 2009-02-23T01:23:54.387 に答える
4

ゼロ除算のチェックを挿入して、 fdiv演算を探すバイナリクラスを処理できます。

Java:

return x.getFloat() / f2;

javap出力:

0:   aload_0
1:   invokevirtual   #22; //Method DivByZero$X.getFloat:()F
4:   fload_1
5:   fdiv
6:   freturn

ゼロ除算のArithemticExceptionをスローする置換コード:

0:   aload_1
1:   invokevirtual   #22; //Method DivByZero$X.getFloat:()F
4:   fstore_2
5:   fload_0
6:   fconst_0
7:   fcmpl
8:   ifne    21
11:  new     #32; //class java/lang/ArithmeticException
14:  dup
15:  ldc     #34; //String / by zero
17:  invokespecial   #36; //Method java/lang/ArithmeticException."<init>":(Ljava/lang/String;)V
20:  athrow
21:  fload_2
22:  fload_0
23:  fdiv
24:  freturn

この処理は、 ASMなどのバイトコード操作APIを使用して実行できます。これは本当に些細なことではありませんが、ロケット科学でもありません。


(コードの動作を変更するのではなく)監視するだけの場合は、デバッガーを使用する方がよいでしょう。探しているものをキャッチする式をどのデバッガーで記述できるかはわかりませんが、独自のデバッガーを作成することは難しくありません。Sun JDKは、JPDAとその使用方法を示すサンプルコードを提供します(jdk / demo / jpda / examples.jarを解凍します)。

ローカルホストのソケットに接続するサンプルコード:

public class CustomDebugger {

    public static void main(String[] args) throws Exception {
        String port = args[0];
        CustomDebugger debugger = new CustomDebugger();
        AttachingConnector connector = debugger.getConnector();
        VirtualMachine vm = debugger.connect(connector, port);
        try {
            // TODO: get & use EventRequestManager
            vm.resume();
        } finally {
            vm.dispose();
        }
    }

    private AttachingConnector getConnector() {
        VirtualMachineManager vmManager = Bootstrap.virtualMachineManager();
        for (Connector connector : vmManager.attachingConnectors()) {
            System.out.println(connector.name());
            if ("com.sun.jdi.SocketAttach".equals(connector.name())) {
                return (AttachingConnector) connector;
            }
        }
        throw new IllegalStateException();
    }

    private VirtualMachine connect(AttachingConnector connector, String port)
            throws IllegalConnectorArgumentsException, IOException {
        Map<String, Connector.Argument> args = connector.defaultArguments();
        Connector.Argument pidArgument = args.get("port");
        if (pidArgument == null) {
            throw new IllegalStateException();
        }
        pidArgument.setValue(port);

        return connector.attach(args);
    }
}
于 2009-02-23T12:14:29.563 に答える
0

それを実現するためにVMに設定できるものは何も知りません。

コードの構造に応じて、次の種類のチェックをメソッドに追加します(これは、ほとんどの場合、習慣から外して行うだけですが、非常に便利です)。

float foo(final float a, final float b)  
{  
    // this check is problematic - you really want to check that it is a nubmer very   
    // close to zero since floating point is never exact.  
    if(b == 0.0f)  
    {  
        throw new IllegalArgumentException("b cannot be 0.0f");  
    }  

    return (a / b);  
}  

浮動小数点数の正確な表現が必要な場合は、java.math.BigDecimalを確認する必要があります。

于 2009-02-23T01:27:29.447 に答える
0

例外をキャッチし、追加のランタイム情報を提供するためにAOP (例: AspectJ )を使用することをお勧めします。

関連する可能性のある 2 つの使用例:

  • NaN が予想される側面を回避し、NaN/Infinity を防止して実行時の情報をログに記録しようとする
  • 例外をキャッチし、ソフトウェアがクラッシュするのを防ぐ側面を書きます

ソフトウェアのデプロイ方法に応じて、さまざまな AOP ウィービング戦略 (実行時、ロード時など) を使用できます。

于 2009-02-23T06:49:50.903 に答える