Java 计算除以2的次数

Java 计算除以2的次数,java,language-agnostic,math,Java,Language Agnostic,Math,你好 我有一个java方法,我认为它很贵,我想用数学表达式来替换它的调用。问题是,我数学不好。我是说真的糟透了 下面应该解释我试图利用的模式 f(x) -> y f(x*2) -> f(x)+1 也就是说,每当我将x的值加倍时,y的值将比x/2的值大1。 以下是一些示例输出: f(5) -> 6 f(10) -> 7 f(20) -> 8 f(40) -> 9 f(80) -> 10 f(160) -> 11 f(320) -&g

你好

<>我有一个java方法,我认为它很贵,我想用数学表达式来替换它的调用。问题是,我数学不好。我是说真的糟透了

下面应该解释我试图利用的模式

f(x)   -> y
f(x*2) -> f(x)+1
也就是说,每当我将x的值加倍时,y的值将比x/2的值大1。 以下是一些示例输出:

f(5)   -> 6
f(10)  -> 7
f(20)  -> 8
f(40)  -> 9
f(80)  -> 10
f(160) -> 11
f(320) -> 12
我目前的做法是暴力。我在X上循环,测试在达到5之前我可以减半多少次,最后我加6。这可以工作,并且比调用原始方法更快。但我正在寻找一种更“优雅”或可能更便宜的解决方案

被接受的答案是:一个在不指出我有多愚蠢的情况下设法帮助我的人:)


(这个标题可能很糟糕,因为我不知道我在找什么)

你有没有考虑过,你要看的基本上是除以5,找出你的2的幂,再加上6

“给定Y,找出X的幂”的一般方法是使用对数。使用计算器,尝试将64的对数除以2,得到6


所以-除以5,取对数,除以2的对数,再加上6。

您正在寻找对数(以2为底)

如果基数
x
为5,基数
y
为6,则log2(320/5)+6=12

在Java中,
(Math.log(320/x)/Math.log(2))+y


其中,
x
y
是原始值(在本例中,
f(5)=6

好的,首先让我们注意所有输入都是5的倍数,因此我们在输入中提取一个系数5;我们注意到输出从6开始,所以我们在输出中按6进行缩放。我将调用这个新函数
g

g(1)      0
g(2)      1
g(4)      2
g(8)      3
g(16)     4
g(32)     5
g(64)     6
现在希望这个函数更为熟悉-
g(x)
x
相比非常简单。要做到这一点(在Java中),我们可以使用
Java.lang.Math.pow(2,x)

剩下的就是从
g
获取
f
。但这很简单:

  • 给定
    f
  • 除以5
  • 用作
    g
  • 加6

我把它留给你。

你要找的是二进制表示法中的位数,它(对于以10为基数的数字和以10为基数的对数)是由log(x)/log(2)给出的。

这不是答案,但我无法对其进行评论。考虑递归函数:

int someFunc(int n, int times) {
  if(n == 0) return 0;
  if( n % 2 == 0) return someFunc(n/2, times+1);
  else return n+times;
}
它能满足你的需要吗

someFunc(1, 0) -> 1
someFunc(2, 0) -> 2
someFunc(3, 0) -> 3
someFunc(5, 0) -> 5
someFunc(10, 0) -> 6
...
试试这个:

f(x) = log<sub>2</sub>(x/5) + 6
f(x)=log2(x/5)+6

首先,你的问题提出得不好。这是一个不应该问问题的例子(无意冒犯)。我认为你的问题是:给定一个正整数x,求整数m,n,使得x=m*2^n,其中m是奇数,然后返回y=f(x)=n+g(m)。因为你们并没有告诉我们f(x)是如何为奇数x计算的,所以我假设g(.)是给定的

如果在您的问题中,n不是很大,那么使用比简单循环(朴素算法)更复杂的算法并没有真正的好处。我将介绍一种算法,它有利于n很大的情况(比如几百、几千)。我不懂Java,所以我以一般形式(使用Python风格的语法)介绍了算法

如果采用x的二进制表示形式(b_{N-1}…b_1 b_0,b_i=0或1),则问题归结为从右侧查找第一位1(即最低有效位1)。假设这个位的位置是k(0k)。我认为找到k最好的方法是使用二进制搜索,这会产生一个O(logn)算法。算法如下(>是移位运算符):

算法:输入:x->输出:(m,n)
如果x是奇数或x==0:当x&1==1或x%2==1时,返回(x,0)#x是奇数
N=ceil(log(x,2))#ceil:比参数大的最小整数
n=0
原点x=x
当x&1==0时:#如果位0为1(即x为奇数),则停止搜索
一半=整数(N/2)
lowerhalf=x&(1>一半
N-=一半
其他:
x=低低频
N=一半
返回(原版>>n,n)

例如,如果N=1000(x是1000位整数),此算法最多需要10次迭代(而朴素算法在最坏的情况下需要1000次迭代)。然而,实际执行时间取决于1000位长度整数的位操作和==运算符的实现方式。

什么是f(0)、f(1)、f(2)、f(3)、f(4)?在您的示例中,您将f(6)定义为等于什么(例如)。或者您的函数仅对x值有效,而x值是起始x的特定倍数?这听起来像是一些奇怪的对数。@thorbjörn:f(0)是非法的。f(1)=4,f(2)=2,f(3)=8,f(4)=3他给出的示例表明,他并不是在寻找二进制表示法中的位数,因为这样所有的位数都是错误的。是的,但我更愿意回答“除以二”部分,并让原始海报填补空白。请注意,同时出现了多个答案:)据我所知,他以5为例。它可以是任意奇数。所以基本上他需要将任意x表示为x*2^n,其中x可以是任意奇数。在问题中遗漏了“示例”。理解为值。örn。是的,我考虑过,但我不知道如何获得2的幂。@Sergey,“任意奇数”在哪里来自?ørn,他在一个循环中被2除,直到不再可能。一个不可能被2除的数是奇数。如果x是偶数,你可以这样做:x*2^n=(x/2)*2^(n+1).这很可能就是我要找的for@Ronnis,你将如何计算基数x?另外,我不确定使用基于双基的Math.log是否比循环中除以2(真的是移位一位)更有效。@Sergey,很好的观点。也许找到基数并应用log hack的成本比仅仅h的成本更高
Algorithm: Input: x -> Outputs: (m, n)

if x is odd or x == 0: return (x, 0)  # x is odd when x & 1 == 1 or x % 2 == 1
N = ceil(log(x, 2))  # ceil: smallest integer larger than the argument
n = 0
orig_x = x

while x & 1 == 0:   # if bit 0 is 1 (i.e. x is odd), stop the search
  half = int(N/2)
  lowerhalf = x & ((1 << half) - 1)  # obtain the lower half
  if lowerhalf == 0:   # all zeros
    n += half
    x = x >> half
    N -= half
  else:
    x = lowerhalf
    N = half

return (orig_x >> n, n)