Java 中的分数简化
我的任务是培养一个理性的班级。如果 500 和 1000 是我的输入,那么 (½) 一定是我的输出。 我自己写了一个程序来找到它。
是否有另一种最佳方法来找到解决方案,或者我的程序已经是最好的方法?
public class Rational {
public static void main(String[] args){
int n1 = Integer.parseInt(args[0]);
int n2 = Integer.parseInt(args[1]);
int temp1 = n1;
int temp2 = n2;
while (n1 != n2){
if(n1 > n2)
n1 = n1 - n2;
else
n2 = n2 - n1;
}
int n3 = temp1 / n1 ;
int n4 = temp2 / n1 ;
System.out.print("\n Output :\n");
System.out.print(n3 + "/" + n4 + "\n\n" );
System.exit(0);
}
}
My task is to develop a rational class. If 500 and 1000 are my inputs, then (½) must be my output.
I have written a program on my own to find it.
Is there another best way to find the solution, or my program is already the best one?
public class Rational {
public static void main(String[] args){
int n1 = Integer.parseInt(args[0]);
int n2 = Integer.parseInt(args[1]);
int temp1 = n1;
int temp2 = n2;
while (n1 != n2){
if(n1 > n2)
n1 = n1 - n2;
else
n2 = n2 - n1;
}
int n3 = temp1 / n1 ;
int n4 = temp2 / n1 ;
System.out.print("\n Output :\n");
System.out.print(n3 + "/" + n4 + "\n\n" );
System.exit(0);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
有趣的问题。下面是一些用最少的代码完成此操作的可执行代码:
奖励方法:
Interesting question. Here's some executable code that does it with minimal code:
Bonus methods:
你需要 GCD。要么像 Nathan 提到的那样使用 BigInteger,要么如果不能,使用你自己的 BigInteger。
然后你可以将每个数字除以 GCD,就像上面所做的那样。
这会给你一个不正确的分数。如果您需要带分数,那么您可以获得新的数字。例如,如果您输入 1500 和 500,您最终会得到 3/2 作为答案。也许你想要 1 1/2。所以你只需除 3/2 得到 1,然后得到 3/2 的余数,也是 1。分母保持不变。
如果你不相信我这有效,你可以看看
http://en.wikipedia.org/wiki/Euclidean_algorithm
我只是碰巧喜欢递归函数因为它干净简单。
您的算法很接近,但并不完全正确。另外,如果你想找到 gcd,你可能应该创建一个新函数。只是让它变得更干净、更容易阅读。您也可以测试该功能。
You need the GCD. Either use BigInteger like Nathan mentioned or if you can't, use your own.
Then you can divide each number by the GCD, like you have done above.
This will give you an improper fraction. If you need a mixed fraction then you can get the new numbers. Example if you had 1500 and 500 for inputs you would end up with 3/2 as your answer. Maybe you want 1 1/2. So you just divide 3/2 and get 1 and then get the remainder of 3/2 which is also 1. The denominator will stay the same.
In case you don't believe me that this works, you can check out
http://en.wikipedia.org/wiki/Euclidean_algorithm
I just happen to like the recursive function because it's clean and simple.
Your algorithm is close, but not exactly correct. Also, you should probably create a new function if you want to find the gcd. Just makes it a little cleaner and easier to read. You can also test that function as well.
作为参考,您实现的是原始减法 欧几里得算法计算最大公约数两个数字。
更快的版本是在循环中使用整数除法的余数,例如
%
而不是-
:...然后确保您将使用不是的那个零。
更精简的版本是这样的:
然后使用n1。马特的答案显示了同一算法的递归版本。
For reference, what you implemented is the original subtractive Euclidean Algorithm to calculate the greatest common divisor of two numbers.
A lot faster version is using the remainder from integer division, e.g.
%
instead of-
in your loop:... and then make sure you will use the one which is not zero.
A more streamlined version would be this:
and then use n1. Matt's answer shows a recursive version of the same algorithm.
您应该使此类不是静态方法的容器。这是一个骨架
You should make this class something other than a container for static methods. Here is a skeleton
我使用了一个类似的 BigRational 类。
GcdFunction
利用了BigInteger
的gcd
函数:BigRational
包含一个BigInteger
> 分子和分母。如果简化比率的分母等于 1,isInteger()
返回 true。I have a similar
BigRational
class I use. TheGcdFunction
is makes use ofBigInteger
'sgcd
function:BigRational
contains aBigInteger
numerator and denominator.isInteger()
returns true if the simplified ratio's denominator is equal to 1.注意到这里的所有答案都没有提到欧几里得算法的迭代实现。
我像 @Bohemian 一样实现了验证测试,递归和迭代实现的工作原理相同,但是迭代方法更快。基准测试显示了很小的改进,但它是改进,总体来说,不要过多使用堆栈并完全依赖 Java VM 来优化其实现依赖,感觉更好。即使基准测试相同,我仍然会对迭代感觉更好,因为迭代更便携,而递归仅由我的主机 Java 优化,但在其他虚拟机上可能没有那么好优化。
基准测试结果(代码位于答案的底部):
符号:
我注意到的一个区别(除了性能之外)是符号的处理方式不同,手工实现的欧几里得算法
gcdLong
和我的gcdLongIterative
行为相同,但两者都与BigInteger
不同,后者倾向于“保持”符号原样。看起来本质上 gcd 和 gcdLongIterative 可以返回负数,而 BigInteger 只会返回正数。用于分数时的所有结果都是有效的,但如果您期望特定“样式”的数字,则值得考虑后处理标准化。
例如,如果首选 BigInteger 行为,那么仅返回绝对值就足够了,如下所示:
性能:
受 @Xabster 基准测试启发(来自 Java:获取最大公约数,哪种方法更好?)我将其扩展以测试所有 3 个实现,但在某些情况下,递归和迭代执行相同的操作在大多数情况下,迭代速度稍快一些。
基准测试代码:
Noticed that all answers here do not mention the iterative implementation of the Euclidean algorithm.
I implemented the validation test like @Bohemian and both recursive and iterative implementations work the same, however the iterative approach is faster. The benchmarks show small improvement, but it's improvement and overall it feels better to not use the stack so much and depend fully on the Java VM to optimize its implementation depend. Even if the benchmarks would be the same I would still feel better with the iterative as that would be more portable while the recursive was only optimized by my host Java, but might not be so well optimized on other's VMs.
Benchmark results (code is on the bottom of the answer):
Signs:
One difference I noticed (besides the performance) is that the signs are handled differently, hand implemented Euclidean algorithm
gcdLong
and mygcdLongIterative
behave the same, but both are different fromBigInteger
which tends to 'keep' the signs as they are. It seems that in essence thegcd
andgcdLongIterative
can return a negative number, while BigInteger will return positive only.All results when used for fractions are valid, but it's worth considering post-process normalization if you expect the numbers in a specific 'style'.
For example, if the BigInteger behavior is preferred, then just returning absolute value should be enough, like here:
Performance:
Inspired by @Xabster benchmark (from Java: Get Greatest Common Divisor, which method is better?) I extended it to test all 3 implementations, in some cases both recursive and iterative were performing the same, however the iterative is slightly faster in most of the cases.
The benchmark code: