programing

BigDecimal to SQL NUMBER: 정밀도보다 큰 값 확인

goodsources 2023. 9. 18. 21:18
반응형

BigDecimal to SQL NUMBER: 정밀도보다 큰 값 확인

제 앱에서 숫자를 BigDecimal로 처리하고 NUMBER(15,5)로 저장합니다.이제 저는 자바에서 BigDecimal 값이 열에 맞는지 제대로 확인해야 합니다. 그러면 SQL을 실행하지 않고도 적절한 오류 메시지를 생성하여 예외를 잡고 벤더 오류 코드를 확인할 수 있습니다.제 데이터베이스는 Oracle 10.3이며, 이러한 오류로 인해 오류 1438이 발생합니다.

구글 검색을 해보니 그런 코드를 찾을 수가 없어서 저는 제 코드를 생각해 냈습니다.하지만 난 이 코드가 정말 만족스럽지 않아요...간단하지만 동시에 정확성을 의심할 만큼 간단합니다.여러 가지 값, 임의의 값, 경계를 가지고 테스트를 해보았는데 효과가 있는 것 같습니다.하지만 제가 숫자에 서툴러서 좀 더 강력하고 테스트가 잘 된 코드를 원합니다.

//no constants for easier reading
public boolean testBigDecimal(BigDecimal value) {
    if (value.scale() > 5)
        return false;
    else if (value.precision() - value.scale() > 15 - 5)
        return false;
    else
        return true;
}

편집: 최근 테스트는 규모를 벗어난 숫자에 대한 예외를 얻지 못했고, 그저 조용히 반올림되었을 뿐이며, 이러한 첫 번째 테스트를 했을 때와 그렇지 않은 것이 무엇이 다른지 잘 모르겠습니다.응용 프로그램이 재정적이기 때문에 이러한 반올림은 허용될 수 없으며 반올림/절단은 (Big Decimal 방법을 통해) 명시적이어야 합니다.예외적으로 이 테스트 방법은 유의하지 않은 숫자를 사용하더라도 원하는 정밀도에 비해 숫자가 너무 크지 않은지 확인해야 합니다.해명이 늦어져서 죄송합니다.

시간 내주셔서 감사합니다.


저는 이 질문이 아직도 궁금합니다.제 코드는 아직 실행 중이고, 정확성이나 실패 상황에 대한 "증명"이나 이런 테스트에 대한 표준 코드는 아직 없습니다.

그래서 현상금을 걸게 될 거야, 바라건대 이것들 중 어떤 것이라도 얻길 바라면서.

다음 regexp도 효과가 있습니다.

public class Big {
    private static final Pattern p = Pattern.compile("[0-9]{0,10}(\\.[0-9]{0,5}){0,1}");

    public static void main(String[] args) {
        BigDecimal b = new BigDecimal("123123.12321");
        Matcher m = p.matcher(b.toString());
        System.out.println(b.toString() + " is valid = " + m.matches());
    }
}

이것은 코드를 테스트하는 또 다른 방법일 수도 있고 코드일 수도 있습니다.regexp는 선택적으로 0에서 10자리 사이의 숫자와 소수점 뒤에 0에서 5자리 사이의 숫자가 필요합니다.제가 생각하기에 사인이 필요한지 아닌지는 잘 몰랐습니다.뭐 이런 거 붙이기.[+-]{0,1}앞으로 하면 될 것 같습니다.

여기 더 나은 수업이 있습니다. 아마도 그리고 부분적인 시험이 있는 시험 수업이 있습니다.

public class Big {
    private static final Pattern p = Pattern.compile("[0-9]{0,10}(\\.[0-9]{0,5}){0,1}");

public static boolean isValid(String s) {
    BigDecimal b = new BigDecimal(s);
    Matcher m = p.matcher(b.toPlainString());
    return m.matches();
    }
}

package thop;

import junit.framework.TestCase;

/**
 * Created by IntelliJ IDEA.
 * User: tonyennis
 * Date: Sep 22, 2010
 * Time: 6:01:15 PM
 * To change this template use File | Settings | File Templates.
 */
public class BigTest extends TestCase {

    public void testZero1() {
        assertTrue(Big.isValid("0"));
    }

    public void testZero2() {
        assertTrue(Big.isValid("0."));
    }

    public void testZero3() {
        assertTrue(Big.isValid("0.0"));
    }

    public void testZero4() {
        assertTrue(Big.isValid(".0"));
    }

    public void testTooMuchLeftSide() {
        assertFalse(Big.isValid("12345678901.0"));
    }

    public void testMaxLeftSide() {
        assertTrue(Big.isValid("1234567890.0"));
    }

    public void testMaxLeftSide2() {
        assertTrue(Big.isValid("000001234567890.0"));
    }

    public void testTooMuchScale() {
        assertFalse(Big.isValid("0.123456"));
    }

    public void testScientificNotation1() {
        assertTrue(Big.isValid("123.45e-1"));
    }

    public void testScientificNotation2() {
        assertTrue(Big.isValid("12e4"));
    }
}

기능의 문제점 중 하나는 어떤 경우에는 너무 제한적일 수 있다는 것입니다.

BigDecimal a = new BigDecimal("0.000005"); /* scale 6 */
a = a.multiply(new BigDecimal("2")); /* 0.000010 */
return testBigDecimal(a); /* returns false */

보시다시피 스케일이 아래로 조정되지 않았습니다.고급 정밀도(1e11/2)로 비슷한 일이 발생하면 지금 당장 테스트를 할 수 없습니다.

좀 더 직접적인 경로를 제안합니다.

public boolean testBigDecimal(BigDecimal value) {
    BigDecimal sqlScale = new BigDecimal(100000);
    BigDecimal sqlPrecision = new BigDecimal("10000000000");
    /* check that value * 1e5 is an integer */
    if (value.multiply(sqlScale)
          .compareTo(value.multiply(sqlScale)
              .setScale(0,BigDecimal.ROUND_UP)) != 0)
        return false;
    /* check that |value| < 1e10 */
    else if (value.abs().compareTo(sqlPrecision) >= 0)
        return false;
    else
        return true;
}

갱신하다

0.000010을 삽입하려고 하면 데이터베이스에 오류가 발생하는지 댓글로 문의하셨습니다.실제로 데이터베이스는 너무 정밀하게 값을 삽입하려고 하면 오류를 발생시키지 않으며, 삽입된 값을 자동으로 반올림합니다.

따라서 Oracle 오류를 피하기 위해 첫 번째 검사가 필요하지 않습니다. 삽입하려는 값이 실제로 삽입한 값과 동일한지 확인하기 위해 이 테스트를 수행하고 있다고 가정했습니다.0.000010과 0.00001이 같으므로(으)BigDecimal.compareTo) 둘 다 같은 결과를 반환해야 하는 것 아닌가요?

대신 수천 개의 난수를 반복하는 경우 소수점 오른쪽에 최대값 +.00001, 최대값, 최대값 -.00001, 0, null, 최소값 -.00001, 최소값, 최소값 +.00001 및 4, 5, 6 값을 강조하는 테스트 케이스를 작성할 수 있습니다.아마 더 많을 겁니다.

그것들을 가지고 있다면, 당신은 좋습니다.

아무도 다른 해결책을 제시하지 않았기 때문에 코드는 그대로 두겠습니다.

저는 이 정밀/규모 테스트를 실패로 만들 수 없었고, 항상 정규 확률 솔루션과 일치했기 때문에 둘 다 맞을 수 있습니다(경계선과 5M 이상의 임의 생성 값을 테스트했습니다).정밀/스케일 솔루션을 사용하겠습니다. 85% 이상 빠르기 때문에 실패할 수도 있기 때문에 교체합니다.

토니, 답장 고마워요.


나의 이전 "답변", 여전히 역사적인 목적으로 여기에 있지만, 나는 진짜 답을 찾고 있습니다 =)

언급URL : https://stackoverflow.com/questions/3772750/bigdecimal-to-sql-number-check-for-value-larger-than-precision

반응형