我得到分母的负数

时间:2013-11-21 00:57:45

标签: java junit fractions greatest-common-divisor

我编写了一个添加两个分数的程序,如果分母为0则应该抛出IllegalArgumentException。当我测试它时,我遇到了失败,当我尝试添加0/2 + -1/2时,我应该-1/2但我获得1/-2,我该如何解决这个问题呢?

语言为德语,bruch表示fractionneuNenner表示new denominatorneuZaehler表示new numeratorggt表示gcd

我删除了

assertEquals("Zaehler = -1 Nenner = 2",
                rechnen.Rechnen.bruchAddition(0, 2, -1, 2));

但后来我收到了这个错误java.lang.AssertionError

这是我的代码:

    public class Rechnen {

    public static String bruchAddition(int z1, int n1, int z2, int n2) {

        int neuZaehler = (z1 * n2) + (z2 * n1);
        int neuNenner = n1 * n2;

        int ggt = ggt(neuZaehler, neuNenner);
        neuZaehler = neuZaehler / ggt;
        neuNenner = neuNenner / ggt;

        if (n1 == 0 || n2 == 0) {
            throw new IllegalArgumentException();
        }
        return ("Zaehler = " + neuZaehler + " Nenner = " + neuNenner);

    }

    static public int ggt(int x, int y) {
        if (y == 0) {
            return x;
        }
        return ggt(y, x % y);
    }
}

这是JUnit测试用例:

import static org.junit.Assert.*;
import org.junit.Test;
public class RechnenTest {
    @Test
    public void test() {
        assertEquals("Zaehler = 1 Nenner = 1",
                rechnen.Rechnen.bruchAddition(1, 3, 2, 3));
        assertEquals("Zaehler = 1 Nenner = 1",
                rechnen.Rechnen.bruchAddition(5, 8, 3, 8));
        assertEquals("Zaehler = 1 Nenner = 1",
                rechnen.Rechnen.bruchAddition(10, 16, 3, 8));
        assertEquals("Zaehler = 1 Nenner = 3",
                rechnen.Rechnen.bruchAddition(-1, 3, 2, 3));
        assertEquals("Zaehler = -1 Nenner = 2",
                rechnen.Rechnen.bruchAddition(0, 2, -1, 2));
        assertEquals("Zaehler = -2 Nenner = 3",
                rechnen.Rechnen.bruchAddition(-1, 3, 1, -3));
        try {
            rechnen.Rechnen.bruchAddition(1, 1, 1, 0);
            fail();
        } catch (IllegalArgumentException e) {
            assertTrue(true);
        }
        try {
            rechnen.Rechnen.bruchAddition(Integer.MAX_VALUE, 1, 1, 1);
            fail();
        } catch (IllegalArgumentException e) {
            assertTrue(true);
        }
        assertEquals("Zaehler = 1 Nenner = " + Integer.MAX_VALUE,
                rechnen.Rechnen.bruchAddition(0, Integer.MAX_VALUE, 1,
                        Integer.MAX_VALUE));
    }
}

2 个答案:

答案 0 :(得分:1)

操作后检查分子和分母上的符号。如果它们都是负数或者分子是正数而分母是负数,则翻转两个符号。

答案 1 :(得分:0)

我不确定Euclid的GCD算法(ggt)是否适用于负数。我想你可能希望ggt的结果总是积极的。最好确保ggt只用正整数调用(或者分子为0):

int ggt = ggt(Math.abs(neuZaehler), Math.abs(neuNenner));

在Java中,如果x为负且y为正数,则x % y为负数,我认为这就是为什么你得到了你得到的负面结果。

编辑:回答第二个问题(为什么你会得到AssertionError):问题是你已经满溢了。您要添加两个分母为分数为Integer.MAX_VALUE的分数,并且您的算法将这两个值相乘以得到neuNenner。当然,这会产生大于Integer.MAX_VALUE的结果,因此neuNenner将具有不正确的值,从而搞乱一切。可能的解决方案:(1)在longbruchAddition内使用ggt值; (2)使用BigInteger,它可以处理任何大小的整数; (3)不要使用Integer.MAX_VALUE进行测试(尝试使用Short.MAX_VALUE); (4)更改bruchAddition以处理n1 == n2(您可以只添加分子)的特殊情况,或n1可被n2整除,反之亦然(您可以将分子乘以n1/n2n2/n1,这样可以避免处理大于n1n2的数字。

编辑2:为了进一步澄清解决方案(1):仅将int的声明更改为long是不行的:

public static String bruchAddition(int z1, int n1, int z2, int n2) {

    long neuZaehler = (z1 * n2) + (z2 * n1);
    long neuNenner = n1 * n2;

因为乘法仍然使用int完成,并且仍会溢出,之前将值转换为long。但是,我已经测试了这个并且它可以工作:

public static String bruchAddition(int z1, int n1, int z2, int n2) {

    long neuZaehler = ((long)z1 * (long)n2) + ((long)z2 * (long)n1);
    long neuNenner = (long)n1 * (long)n2;

确保使用更大的整数大小完成所有计算。同时将ggt方法的结果类型和参数类型更改为long,并将ggt变量更改为long,但您无需执行任何其他投射