不使用 '/' 进行除法
谁能告诉我一种在不使用“/”的情况下执行除法运算的有效方法。我可以使用类似于二分搜索的方法以 log(n)
步计算整数值。
115/3
57 * 3 > 115
28 * 3 < 115
47 * 3 > 115
.
.
.
38 * 3 is quotient value .....
但还有其他更有效的方法吗?
Can anyone tell me an efficient approach to perform the division operation without using '/'. I can calculate the integer value in log(n)
steps using a method similar to binary search.
115/3
57 * 3 > 115
28 * 3 < 115
47 * 3 > 115
.
.
.
38 * 3 is quotient value .....
But is there any other more efficient method?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
典型的方法是移位和减法。这基本上与我们在学校学到的长除法非常相似。最大的区别在于,在小数除法中,您需要估计结果的下一位。在二进制中,这是微不足道的。下一位始终为 0 或 1。如果(左移)除数小于或等于当前被除数值,则将其相减,结果的当前位为 1。如果它更大,则结果的当前位是 0。代码如下所示:
这与我们手动进行长除法时非常相似。例如,我们考虑 972/5。在十进制长除法中,我们这样做:
然后我们单独计算每个数字。 5 会变成 9 一次,所以我们在答案的该数字中记下 1,并从被除数(该数字)中减去 1*5,然后“减去”被除数的下一位:
我们继续做同样的事情直到我们填完所有数字:
所以,我们的答案是 194 余数 2。
现在让我们考虑同样的事情,但是是二进制的。 972 二进制为
11 1100 1100
,5 为101
。现在,二进制与十进制除法之间存在一个根本区别:在十进制中,特定数字可以是 0 到 9 之间的任何数字,因此我们必须进行乘法才能找到要从被除数中减去的中间结果。在二进制中,数字只会是 0 或 1。我们永远不需要相乘,因为我们只会乘以 0 或 1(我们通常在 if 语句中处理 - 要么我们相减,要么不相乘) )。因此,我们的第一步是找出结果中的第一个数字。我们通过比较 101 和 1111001100 并将其左移直到它更大来实现这一点。这给了我们:
当我们进行移位时,我们会计算移位的位置数,这样我们就知道在任何给定时间我们要填写结果的哪一位。我已经用上面的垂直条展示了这一点。然后,我们将中间结果右移一位,并将竖线随之右移,以表示我们要在哪里填充结果数字:
从那里我们检查移动后的除数是否小于被除数。如果是,我们在答案中的适当位置填写 1,并从中间结果中减去移位除数[为了帮助保持列笔直,我将插入一些空格]:
我们继续以同样的方式,填充结果的数字,并从中间结果中减去移位除数,直到填充完所有数字。为了进一步让事情变得简单,我将在减数旁边最右边写下结果的每个数字:
因此,我们得到的结果是 11000010,余数 10。将它们转换为十进制,我们得到预期分别为 194 和 2。
让我们考虑一下这与上面的代码有何关系。我们首先将除数左移,直到它大于被除数。然后,我们反复将其右移,并为每次右移检查该值是否小于上次减法后得到的中间值。如果小于,我们再次减去并在结果中为该数字填充
1
。如果它更大,我们“减去 0”(不做任何事情)并在结果中为该数字填充“0”(这也不需要我们做任何事情,因为这些数字已经设置为0 的)。当我们填完所有数字后,这就是我们的结果,而我们尚未减去的任何金额就是我们的余数。
有人问我为什么在代码中使用
|=
而不是+=
。我希望这有助于解释原因。尽管在这种情况下它们产生相同的结果,但我不考虑将每个数字添加到现有的部分答案中。相反,我认为答案中的那个位置是空的,或
只是填充它。The typical way is to shift and subtract. This is basically pretty similar to long division as we learned it in school. The big difference is that in decimal division you need to estimate the next digit of the result. In binary, that's trivial. The next digit is always either 0 or 1. If the (left-shifted) divisor is less than or equal to the current dividend value, you subtract it, and the current bit of the result is a 1. If it's greater, then the current bit of the result is a 0. Code looks like this:
This works pretty much like when we do long division by hand. For example, let's consider 972/5. In decimal long division, we do something like this:
Then we figure each digit individually. 5 goes into 9 once, so we write down a 1 in that digit of the answer, and subtract 1*5 from (that digit) of the dividend, then "bring down" the next digit of the dividend:
We continue doing the same until we've filled in all the digits:
So, our answer is 194 remainder 2.
Now let's consider the same thing, but in binary. 972 in binary is
11 1100 1100
, and 5 is101
. Now there is one fundamental difference between doing the division in binary vs. decimal: in decimal a particular digit could be anything from 0 to 9, so we had to multiply to find the intermediate result we were going to subtract from the dividend. In binary the digit is only ever going to be a 0 or a 1. We never need to multiply because we would only ever multiply by 0 or 1 (which we normally handle in an if statement--either we subtract or we don't).So, our first step is to figure out which will be the first digit in the result. We do that by comparing 101 to 1111001100, and shifting it left until it's greater. That gives us:
As we do that shifting, we count the number of places we've shifted so we know which digit of the result we're filling in at any given time. I've shown that with the vertical bar above. Then we shift the intermediate result right one place, and shift the vertical bar right with it to signify where we're doing to fill in a result digit:
From there we check if the shifted divisor is less than the dividend. If it is, we fill in a 1 in the proper place in the answer, and subtract the shifted divisor from the intermediate result [and to help keep columns straight, I'm going to insert some spaces]:
We continue the same way, filling in digits of the result, and subtracting the shifted divisor from the intermediate result until we've filled in all the digits. In a further attempt at helping keep things straight, I'm going to write in each digit of the result at the far right next to the subtrahend:
So, we get a result of 11000010, remainder 10. Converting those to decimal, we get the expected 194 and 2 respectively.
Let's consider how that relates to the code above. We start by shifting the divisor left until it's greater than the dividend. We then repeatedly shift it right and for each right shift check whether that value is less than the intermediate we got after the last subtraction. If it's less, we subtract again and fill in a
1
for that digit in our result. If it's greater, we "subtract 0" (don't do anything) and fill in a '0' for that digit in the result (which, again, doesn't require us to do anything, since those digits are already set to 0's).When we've filled in all the digits, that's our result, and any amount left that we haven't subtracted yet is our remainder.
Some have asked why I used
|=
instead of+=
in the code. I hope this helps explain why. Although in this case they produce the same result, I don't think of adding each digit to the existing partial answer. Rather, I think of it that spot in the answer as being empty, and theor
just fills it in.选项:
Options:
使用基本的高中数学进行简单的 Python 实现。分母只是一个负 1 次方的数字。
Simple Python implementation using basic high school math. A denominator is simply a number to the power of negative 1.
以下是不使用除法运算符对数字进行除法的 Java 代码。
Following is the Java code for dividing number without using division operator.
(这是针对不允许使用乘法的问题的解决方案)。
我喜欢这个解决方案:https://stackoverflow.com/a/5387432/1008519,但我发现有点困难原因(尤其是
|
部分)。这个解决方案在我看来更有意义:以下是一些测试运行:
这是一个要点处理除数为 0 的情况以及负除数和/或除数: https://gist.github.com/mlunoe /e34f14cff4d5c57dd90a5626266c4130
(This is a solution to the problem where you are not allowed to use multiplication either).
I like this solution: https://stackoverflow.com/a/5387432/1008519, but I find it somewhat hard to reason about (especially the
|
-part). This solution makes a little more sense in my head:Here are some test runs:
Here is a gist handling both the 0 divisor case and negative dividend and/or divisor: https://gist.github.com/mlunoe/e34f14cff4d5c57dd90a5626266c4130
既然OP说这是一个面试问题,我认为面试官除了看你的编码能力之外还想看以下的东西。 (假设您使用的是Java)
如何处理负数?将被除数和除数都转换为正数是很常见的。但是,您可能会忘记
Math.abs(Integer.MIN_VALUE)
仍然是Integer.MIN_VALUE
。因此,当被除数为Integer.MIN_VALUE时,应单独计算。“Integer.MIN_VALUE/-1”的结果是什么? Integer 中没有这样的值。你应该和面试官讨论一下。您可以针对这种情况引发异常。
这是这个问题的Java代码,您可以验证它leetcode:除两个整数:
Since the OP said it's an interview question, I think the interviewer wants to see the following things in addition to your coding skills. (Suppose you are using Java)
How to deal with negative numbers? It's common to convert both the dividend and the divisor to positive numbers. However, you may forget that
Math.abs(Integer.MIN_VALUE)
is stillInteger.MIN_VALUE
. Therefore, when the dividend is Integer.MIN_VALUE, you should calculate it separately.What's the result of "Integer.MIN_VALUE/-1"? There is no such value in Integer. You should discuss it with the interviewer. You can throw an exception for this condition.
Here is the Java code for this question and you can validate it leetcode:divide two integers:
主要概念:
假设我们计算
20/4
,所以代码:
The main concept :
Let's say we are calc
20/4
, soThe code:
不使用 / 进行两个数字相除
Division of two numbers without using /
这是一个不使用“/”运算符的简单整数除法:-
Here is a simple divide method for ints without using a '/' operator:-
这是 JavaScript 中的一个:
可以通过在精度的最后一位小数后四舍五入来进一步改进。
Here's one in JavaScript:
It could be further improved by rounding after the last decimal place of the precision.
也许您可以设计一种使用>>序列来做到这一点的方法。 (位移位)与其他按位运算符。 维基百科:按位运算符文章中有一个伪代码示例。
Perhaps you can devise a way to do it using sequences of >> (bit shifts) with other bitwise operators. There's an example in psuedo-code in the Wikipedia: Bitwise Operator article.
好吧,如果这只是整数/整数 = int 类型除法,那么很容易得到 x / n = int.dec 的整数部分,方法是添加 n+n+n+n 直到 n 大于 x,然后从你的数。
要在不使用 *、/、% 或其他数学函数的情况下获得 int/int = real,您可以执行以下操作。例如,您可以将余数作为有理数返回。这样做的优点是准确。您还可以使用字符串修改将 r 转换为 r0...(您选择精度),然后重复相同的加法技巧,然后连接结果。
当然,您可以尝试享受位移位的乐趣。
我不知道这是否是一个“愚蠢的把戏”,因为它是对你如何使用简单的东西(加法、减法)来构建复杂的东西(除法)的测试。这是您的潜在雇主可能需要的一项技能,因为没有一个操作员可以处理所有事情。像这样的问题(理论上)应该把不能设计算法的人从能设计算法的人中淘汰掉。
我确实认为答案在互联网上如此容易获得是一个问题,但这是一个实施问题。
Well, if this is only integer/integer = int type division, it's pretty easy to get the integer part of x / n = int.dec by adding n+n+n+n until n is greater than x, then subtracting one from your 'n' count.
To get int/int = real without using *, /, %, or other math functions, you could do several things. You could return the remainder as a rational, for example. That has the advantage of being exact. You could also use string modification to turn your r into r0... (you pick the precision) and then repeat the same addition trick, then concatenate the results.
And of course, you could try having fun with bit shifting.
I don't know if this is so much a 'silly trick' as it is a test of how well you can use simple things (addition, subtraction) to build a complex thing (division). This is a skill that your potential employer might need, because there isn't an operator for everything. A question like this should (theoretically) weed out people who can't design algorithms from people who can.
I do think it's a problem that the answer is so readily available on the internet, but that's an implementation issue.
这是解决我的问题的函数:
This is the function that solved my problem:
如果你把除法当作减法,它基本上是什么,你可以使用一种“减量”方法,它允许你根本不使用任何运算符,除了最后的 ~ ,稍后将结果反转为正整数或任何其他值。
If you take the division as a subtraction, what it basically is, you could use a method "decrement" what allows you to not use any operator at all, except for ~ at the end, to invert the result later into a positive integer or any other value.
好吧,让我们看看... x/y = e^(ln(x)-ln(y))
well, let's see... x/y = e^(ln(x)-ln(y))