面试问题:f(f(x))== 1 / x

时间:2009-04-09 01:38:13

标签: math

  

设计一个函数f:

     

f(f(x))== 1 / x

     

其中x是32位浮点数

或者怎么样

  

给定函数f,找到函数g   这样

     

f(x)== g(g(x))


另请参阅

  

Interview question: f(f(n)) == -n

10 个答案:

答案 0 :(得分:23)

对于第一部分:这一部分比f(f(x))= -x更为平凡,IMO:

float f(float x)
{
    return x >= 0 ? -1.0/x : -x;
}

第二部分是一个有趣的问题,这个问题的基础是the original question的明显概括。有两种基本方法:

  • 一种数值方法,使得x≠f(x)≠f(f(x)),我认为这更符合原问题的精神,但我认为在一般情况下是不可能的< / LI>
  • 一种涉及g(g(x))恰好调用f的方法

答案 1 :(得分:12)

嗯,这是C快攻:

extern double f(double x);
double g(double x)
{
  static int parity = 0;
  parity ^= 1;
  return (parity ? x : f(x));
}

但是,如果你这样做会失败:

a = g(4.0); // => a = 4.0, parity = 1
b = g(2.0); // => b = f(2.0), parity = 0
c = g(a);   // => c = 4.0, parity = 1
d = g(b);   // => d = f(f(2.0)), parity = 0

一般来说,如果f是双射f:D→D,你需要的是一个函数σ,它将域D划分为A和B,这样:

  1. D =A∪B,(分区是合计的)
  2. ∅=A∩B(分区不相交)
  3. σ(a)∈B,f(a)∈A∀a∈A,
  4. σ(b)∈A,f(b)∈B∀b∈B,
  5. σ具有反σ -1 s.t. σ(σ -1 (d))=σ -1 (σ(d))=d∀d∈D。
  6. σ(f(d))= f(σ(d))∀d∈D
  7. 然后,你可以这样定义g:

    • g(a)=σ(f(a))∀a∈A
    • g(b)=σ -1 (b)∀b∈B

    这适用于b / c

    • ∀a∈A,g(g(a))= g(σ(f(a))。由(3),f(a)∈A所以σ(f(a))∈Bso g( σ(f(a))=σ -1 (σ(f(a)))= f(a)。
    • ∀b∈B,g(g(b))= g(σ -1 (b))。由(4),σ -1 (b)∈A所以g(σ -1 (b))=σ(f(σ -1 (b)))= f(σ(σ -1 (b)))= f(b)。

    你可以从Miles回答中看到,如果我们忽略0,那么操作σ(x)= -x适用于f(x)= 1 / x。您可以检查1-6(对于D =非零实数),A为正数,B为负数。使用双精度标准,有一个+0,一个-0,一个+inf和一个-inf,这些可用于使域总数(适用于所有双精度数,而不仅仅是非零数。)

    同样的方法可以应用于f(x)= -1问题 - 使用σ(x)=(x - 1)将剩余的mod 2分隔空间的接受解决方案,特别处理零情况

答案 2 :(得分:11)

我喜欢早期帖子中的javascript / lambda建议:

function f(x)
{
   if (typeof x == "function")
       return x();
   else
       return function () {return 1/x;}
}

答案 3 :(得分:2)

其他解决方案暗示需要额外的状态。以下是对此的更多数学证明:

let f(x) = 1/(x^i)= x^-i

(其中^表示指数,i是虚常数sqrt(-1))

f(f(x)) = (x^-i)^-i) = x^(-i*-i) = x^(-1) = 1/x

因此存在复杂数字的解决方案。我不知道是否有一般性解决方案严格遵守实数。

答案 4 :(得分:1)

同样,它被指定为32位数字。使返回有更多位,使用它们在调用之间传递状态信息。

Const
    Flag = $100000000;

Function F(X : 32bit) : 64bit;

Begin
    If (64BitInt(X) And Flag) > 0 then
        Result := g(32bit(X))
    Else
        Result := 32BitInt(X) Or Flag;
End;

对于任何函数g和任何32位数据类型32位。

答案 5 :(得分:1)

还有另一种解决方法,它使用分数线性变换的概念。这些是发送x->(ax + b)/(cx + d)的函数,其中a,b,c,d是实数。

例如,您可以使用某些代数证明,如果f由f(x)=(ax + 1)( - x + d)定义,其中a ^ 2 = d ^ 2 = 1且a + d&lt;&gt; 0然后对于所有实数x,f(f(x))= 1 / x。选择a = 1,d = 1,这就解决了C ++中的问题:

float f(float x)
{
    return (x+1)/(-x+1);
}

证明是f(f(x))= f((x + 1)/( - x + 1))=((x + 1)/( - x + 1)+1)/( - ( X + 1)/( - X + 1)+1)                                     抵消(1-x)时=(2 /(1-x))/(2x /(1-x))= 1 / x。

除非我们允许定义满足1 / inf = 0,1 / 0 = inf的“无限”值,否则这对x = 1或x = 0不起作用。

答案 6 :(得分:1)

g(g(x)) == f(x)的C ++解决方案:

struct X{
    double val;
};

X g(double x){
    X ret = {x};
    return ret;
}

double g(X x){
    return f(x.val);
}

这是一个更短的版本(我更喜欢这个:-))

struct X{
    X(double){}
    bool operator==(double) const{
        return true
    }
};

X g(X x){
    return X();
}

答案 7 :(得分:1)

如果f(x) == g(g(x)),则g被称为f的{​​{3}}。即使你允许 x 复杂,我也不认为有一般的封闭形式(你可能想去mathoverflow讨论:))。

答案 8 :(得分:0)

基于this answer,广义版本的解决方案(作为Perl单线程):

sub g { $_[0] > 0 ? -f($_[0]) : -$_[0] }

应始终翻转变量的符号(a.k.a.状态)两次,并且应始终只调用f()一次。对于那些不足以获得Perl隐含回报的语言,只需在return之前点击{,就可以了。

只要f()不更改变量的符号,此解决方案就可以正常工作。在这种情况下,它返回原始结果(对于负数)或f(f())的结果(对于正数)。替代方法可以将变量的状态存储为偶数/奇数,就像前一个问题的答案一样,但如果f()改变(或可以改变)变量的值,它就会中断。如前所述,更好的答案是lambda解决方案。这是Perl中类似但不同的解决方案(使用引用,但概念相同):

sub g {
  if(ref $_[0]) {
    return ${$_[0]};
  } else {
    local $var = f($_[0]);
    return \$var;
  }
}

注意:这已经过测试,并且有效。它总是返回对标量的引用(并且它始终是相同的引用)。我已经尝试了一些东西,但是这段代码显示了一般的想法,虽然我的实现是错误的,并且方法甚至可能有缺陷,但它是朝着正确方向迈出的一步。有了一些技巧,你甚至可以使用一个字符串:

use String::Util qw(looks_like_number);

sub g {
  return "s" . f($_[0]) if looks_like_number $_[0];
  return substr $_[0], 1;
}

答案 9 :(得分:-1)

试试这个

MessageBox.Show( "x = " + x );
MessageBox.Show( "value of x + x is " + ( x + x ) );
MessageBox.Show( "x =" );
MessageBox.Show( ( x + y ) + " = " + ( y + x ) );