javaの数値範囲及びfloatとdoubleの精度が失われた問題を解決します。


1.javaでint、float、long、doubleで値を取る範囲

public class TestOutOfBound { 
public static void main(String[] args) { 
 
System.out.println(Integer.MAX_VALUE-(-Integer.MAX_VALUE)); //     
System.out.println(Integer.MAX_VALUE); //2 31  -1,10   ,  20   ,          
System.out.println(Integer.MIN_VALUE); //  2 31   
System.out.println(Long.MAX_VALUE); //2 64  -1,19   ,   ,         
System.out.println(Long.MIN_VALUE); //  2 64   
System.out.println(Float.MAX_VALUE); //2 128  -1,38   , long    ,                  
System.out.println(Float.MIN_VALUE); //2 -149   
System.out.println(Double.MAX_VALUE); //2 1024  -1,308   , float   10 ,               
System.out.println(Double.MIN_VALUE); //2 -1074   
 
} 
} 
2.floatとdoubleの精度が問題を失う
例:

  :double result = 1.0 - 0.9; 
 
         ,    ,0.09999999999999998
なぜこの問題が発生しましたか?これはjavaと他のコンピュータ言語で発生する問題です。次に私達はなぜこの問題が発生したのかを分析します。
floatとdoubleタイプは主に科学計算と工程計算のために設計されています。彼らはバイナリ浮動小数点演算を実行しています。これは広範な数字範囲で比較的正確な高速近似計算を提供するために、丹念に設計されました。しかし、それらは完全に正確な結果を提供していないので、正確な計算の場合には使用してはいけません。floatとdoubleのタイプは特に通貨演算に適していません。floatまたはdoubleの正確な表現を0.1または10にするためには、他の負の乗数のいずれかの値は不可能です。同じバイナリシステムでも1/10を正確に表現できませんでした。
浮動小数点演算が少ないのは正確であり、精度を超えて表現できる範囲であれば誤差が生じる。誤差が生じるのは、数の大きさではなく、数の精度のためです。したがって、結果は近いが、欲しい結果には等しくない。特にfloatやdoubleを使って正確な演算をする時は注意が必要です。
浮動小数点型演算はなぜ精度を失うのかを詳しく分析します。

              : 
 
  (1)                
 
          。    ,11       : 
 
          11/2=5    1 
 
           5/2=2     1 
 
           2/2=1     0 
 
           1/2=0     1 
 
            0       11      (    ):1011 
 
         :           0     ,     ,       2           0。    ,                         ?    ,               ,        。 
 
  (2)                
 
          2         。    ,0.9        
 
          0.9*2=1.8        1 
 
          0.8(1.8     )*2=1.6        1 
 
          0.6*2=1.2        1 
 
          0.2*2=0.4        0 
 
          0.4*2=0.8        0 
 
          0.8*2=1.6       1 
 
          0.6*2=1.2        0 
 
              .........   0.9      (    ): 1100100100100...... 
 
       :          ,    *2           ,         。   ,                  。       ,              1/3 ?              1/10。                 "   "       。
3.解決方法一:
十進数の小数点を自分で記録することを気にしないで、しかも数値は大きくないなら、long、intなどの基本的なタイプを使って、具体的にintまたはlongで関連する数値の範囲の大きさを見て、欠点は自分で10進数の小数点を処理するので、最も明らかな方法は貨幣を処理して点数を使って計算して、元(プラスマイナスだけに関連します)を使いません。
例えば:

int resultInt = 10 - 9;  
double result = (double) resultInt / 100;//             
4.解決方法2:
BigDecmalを使用するとともに、構造パラメータにStringタイプを使用する必要があります。
「Effective Java」という本の中で解決方法を示しました。floatとdoubleは科学的な計算や工程計算にしか使えないと指摘しています。商業計算などの正確な計算の中で、java.mash.Big Decimalを使います。
BigDecimal類には4つの方法があります。私たちは浮動小数点型データを正確に計算するために有用な方法、すなわち
BigDecimal/double型データをBigDecimal型データに変換する。
考え方は簡単です。まずBigDecimal方法によって、double型データをBigDecimalデータに変換して、正常に正確に計算することができます。計算が終わったら、私たちは結果をいくつか処理します。例えば、割り切れない結果は四捨五入できます。最後に、結果をBigDecimal型データからdouble型データに変換します。
この考えは正しいですが、APIのBigDecimalに関する詳細な説明をよく見てみると、正確な計算が必要なら、私たちは直接にdoubleを使うことができません。したがって、私たちはBigDecimal類のもう一つの方法に関心を持ち始めました。つまり、正確な計算を正確に行うBigDecimal方法を助けてくれます。
//BigDecimal(String value)String型データをBigDecimal型データに変換することができます。
問題です。もし浮動小数点型のデータを足し算するなら、まず二つの浮動小数点をString型のデータに変えて、Big DecimalでBig Decimalにして、その後一つにaddメソッドを呼び出して、もう一つのパラメータにして、演算の結果をBigDecimalで再浮動小数点に変換します。浮動小数点型のデータを計算するたびに、このような煩雑なプロセスを我慢できますか?少なくとも私はできません。ですから、一番いい方法はクラスを書いて、クラスの中でこれらの煩雑な転換過程を完成することです。このように、浮動小数点型のデータ計算が必要な場合は、このクラスを呼び出してもいいです。インターネット上ではすでに上手な人がいます。これらの変換操作を完了するためにツールクラスのArtithを提供しています。浮動小数点型データの加減乗除演算とその結果を四捨五入する動作を行うための静的な方法を提供する。
public static double add(double v 1,double v 2)
public static double sub(double v 1,double v 2)
public static double mull(double v 1,double v 2)
public static double div(double v 1,double v 2)
public static double div(double v 1,double v 2,int scale)
public static double round(double v、int scale)
Aithのソースコードを添付します。みんなはそれをコンパイルして保存して、浮動小数点の計算を行う時、あなたのソースプログラムにArth類を導入すれば、以上の静的な方法で浮動小数点の正確な計算ができます。
付録:Aithソースコード

import java.math.BigDecimal; 
 
/** 
*   Java                   ,         
*        ,           。 
*/ 
 
public class Arith{ 
  //         
  private static final int DEF_DIV_SCALE = 10; 
  //         
  private Arith(){ 
  } 
 
  /** 
   *          。 
   * @param v1     
   * @param v2    
   * @return        
   */ 
  public static double add(double v1,double v2){ 
    BigDecimal b1 = new BigDecimal(Double.toString(v1)); 
    BigDecimal b2 = new BigDecimal(Double.toString(v2)); 
    return b1.add(b2).doubleValue(); 
  } 
  /** 
   *          。 
   * @param v1     
   * @param v2    
   * @return        
   */ 
  public static double sub(double v1,double v2){ 
    BigDecimal b1 = new BigDecimal(Double.toString(v1)); 
    BigDecimal b2 = new BigDecimal(Double.toString(v2)); 
    return b1.subtract(b2).doubleValue(); 
  } 
  /** 
   *          。 
   * @param v1     
   * @param v2    
   * @return        
   */ 
  public static double mul(double v1,double v2){ 
    BigDecimal b1 = new BigDecimal(Double.toString(v1)); 
    BigDecimal b2 = new BigDecimal(Double.toString(v2)); 
    return b1.multiply(b2).doubleValue(); 
  } 
 
  /** 
   *   (  )       ,          ,    
   *      10 ,         。 
   * @param v1     
   * @param v2    
   * @return        
   */ 
  public static double div(double v1,double v2){ 
    return div(v1,v2,DEF_DIV_SCALE); 
  } 
 
  /** 
   *   (  )       。          , scale    
   *    ,         。 
   * @param v1     
   * @param v2    
   * @param scale                 。 
   * @return        
   */ 
  public static double div(double v1,double v2,int scale){ 
    if(scale<0){ 
      throw new IllegalArgumentException( 
        "The scale must be a positive integer or zero"); 
    } 
    BigDecimal b1 = new BigDecimal(Double.toString(v1)); 
    BigDecimal b2 = new BigDecimal(Double.toString(v2)); 
    return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue(); 
  } 
 
  /** 
   *               。 
   * @param v           
   * @param scale          
   * @return          
   */ 
  public static double round(double v,int scale){ 
 
    if(scale<0){ 
      throw new IllegalArgumentException( 
        "The scale must be a positive integer or zero"); 
    } 
    BigDecimal b = new BigDecimal(Double.toString(v)); 
    BigDecimal one = new BigDecimal("1"); 
    return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue(); 
  } 
}; 
以上の問題はJavaの数値範囲とfloatとdoubleの精度が失われた問題を解決しました。小編集が皆さんに共有している内容の全部です。参考にしていただければと思います。どうぞよろしくお願いします。