모든 반올림을 제외 할 정도로 모든 수학을 완전히 정의하고 제어 할 수 없다면 안된다고 생각합니다.
대안으로는 아마도 Rationals를 사용할 수 있습니다. 여기에 실험으로 기절 한 사례가 있습니다. 최적인지, 아니면 효율적인지는 의심 스럽지만 확실한 가능성은 있습니다.
class Rational {
private int n; // Numerator.
private int d; // Denominator.
Rational(int n, int d) {
int gcd = gcd(n, d);
this.n = n/gcd;
this.d = d/gcd;
}
Rational add(Rational r) {
int lcm = lcm(d, r.d);
return new Rational((n * lcm)/d + (r.n * lcm)/r.d, lcm);
}
Rational sub(Rational r) {
int lcm = lcm(d, r.d);
return new Rational((n * lcm)/d - (r.n * lcm)/r.d, lcm);
}
Rational mul(Rational r) {
return new Rational(n * r.n, d * r.d);
}
Rational div(Rational r) {
return new Rational(n * r.d, d * r.n);
}
@Override
public String toString() {
return n + "/" + d;
}
/**
* Returns the least common multiple between two integer values.
*
* @param a the first integer value.
* @param b the second integer value.
* @return the least common multiple between a and b.
* @throws ArithmeticException if the lcm is too large to store as an int
* @since 1.1
*/
public static int lcm(int a, int b) {
return Math.abs(mulAndCheck(a/gcd(a, b), b));
}
/**
* Multiply two integers, checking for overflow.
*
* @param x a factor
* @param y a factor
* @return the product <code>x*y</code>
* @throws ArithmeticException if the result can not be represented as an
* int
* @since 1.1
*/
public static int mulAndCheck(int x, int y) {
long m = ((long) x) * ((long) y);
if (m < Integer.MIN_VALUE || m > Integer.MAX_VALUE) {
throw new ArithmeticException("overflow: mul");
}
return (int) m;
}
/**
* <p>
* Gets the greatest common divisor of the absolute value of two numbers,
* using the "binary gcd" method which avoids division and modulo
* operations. See Knuth 4.5.2 algorithm B. This algorithm is due to Josef
* Stein (1961).
* </p>
*
* @param u a non-zero number
* @param v a non-zero number
* @return the greatest common divisor, never zero
* @since 1.1
*/
public static int gcd(int u, int v) {
if (u * v == 0) {
return (Math.abs(u) + Math.abs(v));
}
// keep u and v negative, as negative integers range down to
// -2^31, while positive numbers can only be as large as 2^31-1
// (i.e. we can't necessarily negate a negative number without
// overflow)
/* assert u!=0 && v!=0; */
if (u > 0) {
u = -u;
} // make u negative
if (v > 0) {
v = -v;
} // make v negative
// B1. [Find power of 2]
int k = 0;
while ((u & 1) == 0 && (v & 1) == 0 && k < 31) { // while u and v are
// both even...
u /= 2;
v /= 2;
k++; // cast out twos.
}
if (k == 31) {
throw new ArithmeticException("overflow: gcd is 2^31");
}
// B2. Initialize: u and v have been divided by 2^k and at least
// one is odd.
int t = ((u & 1) == 1) ? v : -(u/2)/* B3 */;
// t negative: u was odd, v may be even (t replaces v)
// t positive: u was even, v is odd (t replaces u)
do {
/* assert u<0 && v<0; */
// B4/B3: cast out twos from t.
while ((t & 1) == 0) { // while t is even..
t /= 2; // cast out twos
}
// B5 [reset max(u,v)]
if (t > 0) {
u = -t;
} else {
v = t;
}
// B6/B3. at this point both u and v should be odd.
t = (v - u)/2;
// |u| larger: t positive (replace u)
// |v| larger: t negative (replace v)
} while (t != 0);
return -u * (1 << k); // gcd is u*2^k
}
static void test() {
Rational r13 = new Rational(1, 3);
Rational r29 = new Rational(2, 9);
Rational r39 = new Rational(3, 9);
Rational r12 = new Rational(1, 2);
Rational r59 = r13.add(r29);
Rational r19 = r29.mul(r12);
Rational r23 = r39.div(r12);
Rational r16 = r12.sub(r13);
System.out.println("1/3 = " + r13);
System.out.println("2/9 = " + r29);
System.out.println("1/3 = " + r39);
System.out.println("5/9 = " + r59);
System.out.println("1/9 = " + r19);
System.out.println("2/3 = " + r23);
System.out.println("1/6 = " + r16);
}
}
나는
java2에서 LCM 및 GCD 코드를 발견했다. 그들은 아마도 향상시킬 수 있습니다.
문제를 충분히 자세히 설명하지 않았습니까? – antlersoft
은 2 자리 정밀도를 원한다고 가정합니다. 0.01/10에서 기대할 것입니다. * 10. 할 것? 0 또는 0.01을 반환합니까? 나중에 - 유한 비트 수가 충분하지 않은 경우이를 달성 할 수 있습니다. – amit
질문을 업데이트합니다. –