2

我想测试一个双精度为 3 或更少的最大精度。在 Java 中执行此操作的最佳方法是什么?

20.44567567 <- Fail
20.444 <- Pass
20.1 <- Pass
20 <- Pass
4

4 回答 4

5

1)不要使用double。浮点逻辑充其量是近似的。改为使用BigDecimal

2)我认为BigDecimal已经有一种设置精度的方法。如果没有,只需乘以 1000 并截断。做操作,得到一个新的数字,和原来的比较。如果不同,则失败。

于 2013-03-29T20:04:11.023 回答
1

这通过了您的测试:

package com.sandbox;

import org.junit.Test;

import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;

public class SandboxTest {


    @Test
    public void testPrecision() {
        assertFalse(precisionLessThanOrEqualTo3(20.44567567));
        assertTrue(precisionLessThanOrEqualTo3(20.444));
        assertTrue(precisionLessThanOrEqualTo3(20.1));
        assertTrue(precisionLessThanOrEqualTo3(20));
    }

    private boolean precisionLessThanOrEqualTo3(double x) {
        return String.valueOf(x).replaceAll(".*\\.", "").length() <= 3;
    }
}
于 2013-03-29T20:07:29.897 回答
1

您可以使用以下代码:

boolean f (double in){
    if (in*1000 > (float)(int)(in*1000))
        return false;
    return true;
}
于 2013-03-29T20:07:59.620 回答
0

术语“精度”有多种可能的解释:

  • 算术精度是有效数字的总数(小数点前后)。
  • 数字小数部分的位数(或小数位数)。
  • 特别是在数据库中,可以使用计数中包含的固定小数位数(比例)来测量精度,因此一NUMBER(6,2)列将存储最多 6 位的数字,这些数字始终由 2 位小数和 4 位整数组成。

对于您的示例,您似乎将精度测量为最大小数位数。

这些中的每一个都可以使用以下方法进行测试:

import java.math.BigDecimal;

import org.junit.Test;
import static org.junit.Assert.*;


public class Precision
{
  /**
   * Tests to see whether the number has up to the given number of
   * decimal places.
   * 
   * @param value The value to test.
   * @param scale The maximum number of decimal places. 
   * @return      <code>true</code> if the value has up to the
   *              expected number of decimal places.
   */
  static final boolean hasDecimalPlaces(
      final double value,
      final int    scale
  )
  {
    try
    {
      new BigDecimal( Double.toString( value ) ).setScale( scale );
      return true;
    }
    catch ( final ArithmeticException ex )
    {
      return false;
    }
  }

  /**
   * Tests to see whether the number has up to the given number of
   * significant figures.
   * 
   * @param value     The value to test.
   * @param precision The maximum number of significant figures to
   *                  test for.
   * @return          <code>true</code> if the value has up to the
   *                  expected number of significant figures. 
   */
  static final boolean hasSignificantFigures(
      final double value,
      final int    precision
  )
  {
    try
    {
      return new BigDecimal( Double.toString( value ) ).stripTrailingZeros().precision() <= precision;
    }
    catch ( final ArithmeticException ex )
    {
      return false;
    }
  }

  /**
   * Tests to see whether the number has at most the given number of
   * decimal places and, when represented at that maximum number of
   * decimal places, has up to the given number of digits.
   * 
   * @param value     The number to test.
   * @param precision The maximum number of digits to test for.
   * @param scale     The maximum number of decimal places.
   * @return          <code>true</code> if the value can be represented
   *                  at the given scale and, at that scale, is up to
   *                  the given precision.
   */
  static final boolean hasDigitsAtScale(
      final double value,
      final int    precision,
      final int    scale
  )
  {
    try
    {
      return new BigDecimal( Double.toString( value ) ).setScale( scale ).precision() <= precision;
    }
    catch ( final ArithmeticException ex )
    {
      return false;
    }
  }

  @Test
  public void testScale(){
    assertTrue( hasDecimalPlaces( 20d, 3 ) );
    assertTrue( hasDecimalPlaces( 20.123d, 3 ) );
    assertFalse( hasDecimalPlaces( 20.1234d, 3 ) );
  }

  @Test
  public void testPrecision(){
    assertTrue(  hasSignificantFigures(    20d,      3 ) );
    assertTrue(  hasSignificantFigures(   120d,      3 ) );
    assertTrue(  hasSignificantFigures(  1230d,      3 ) );
    assertFalse( hasSignificantFigures( 12340d,      3 ) );
    assertTrue(  hasSignificantFigures(    20.1d,    3 ) );
    assertFalse( hasSignificantFigures(    20.12d,   3 ) );
    assertTrue(  hasSignificantFigures(     0.123d,  3 ) );
    assertFalse( hasSignificantFigures(     0.1234d, 3 ) );
    assertTrue(  hasSignificantFigures(     0.0000999d,  3 ) );
    assertFalse( hasSignificantFigures(     0.00009999d, 3 ) );
  }

  @Test
  public void testPrecisionAndScale(){
    assertTrue(  hasDigitsAtScale(     0d,      3, 0 ) );
    assertFalse( hasDigitsAtScale(     0.01d,   3, 0 ) );
    assertFalse( hasDigitsAtScale(     0.1d,    3, 0 ) );
    assertTrue(  hasDigitsAtScale(     1d,      3, 0 ) );
    assertTrue(  hasDigitsAtScale(    10d,      3, 0 ) );
    assertTrue(  hasDigitsAtScale(   100d,      3, 0 ) );
    assertFalse( hasDigitsAtScale(  1000d,      3, 0 ) );
    assertFalse( hasDigitsAtScale( 10000d,      3, 0 ) );

    assertTrue(  hasDigitsAtScale(     0d,      3, 1 ) );
    assertFalse( hasDigitsAtScale(     0.01d,   3, 1 ) );
    assertTrue(  hasDigitsAtScale(     0.1d,    3, 1 ) );
    assertTrue(  hasDigitsAtScale(     1d,      3, 1 ) );
    assertTrue(  hasDigitsAtScale(    10d,      3, 1 ) );
    assertFalse( hasDigitsAtScale(   100d,      3, 1 ) );
    assertFalse( hasDigitsAtScale(  1000d,      3, 1 ) );
    assertFalse( hasDigitsAtScale( 10000d,      3, 1 ) );

    assertTrue(  hasDigitsAtScale(     0d,      3, -1 ) );
    assertFalse( hasDigitsAtScale(     0.01d,   3, -1 ) );
    assertFalse( hasDigitsAtScale(     0.1d,    3, -1 ) );
    assertFalse( hasDigitsAtScale(     1d,      3, -1 ) );
    assertTrue(  hasDigitsAtScale(    10d,      3, -1 ) );
    assertTrue(  hasDigitsAtScale(   100d,      3, -1 ) );
    assertTrue(  hasDigitsAtScale(  1000d,      3, -1 ) );
    assertFalse( hasDigitsAtScale( 10000d,      3, -1 ) );
  }
}
于 2019-01-23T11:53:06.297 回答