【问题标题】:Interview question: f(f(x)) == 1/x面试题:f(f(x)) == 1/x
【发布时间】:2010-10-18 11:08:01
【问题描述】:

设计一个函数 f 使得:

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

其中 x 是 32 位浮点数

或者怎么样

给定一个函数 f,求一个函数 g 这样

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


另见

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

【问题讨论】:

  • 我感觉到这些东西正在涌入...
  • 是面试周吗?还是有人在审核面试问题?
  • “灵感”?这就像同一个问题!
  • 他不是得到面试问题的人。他在这里复制面试问题:stackoverflow.com/questions/731832/interview-question-ffn-n
  • 问面试官的问题:“这究竟如何证明你作为一名专业开发人员的技能?”

标签: math


【解决方案1】:

试试这个

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

【讨论】:

  • 此答案在其当前版本中缺少描述和代码缩进(在每个代码行前添加四个空格)。请考虑编辑它。
【解决方案2】:

如果f(x) == g(g(x)),则g 被称为functional square rootf。即使您允许 x 复杂,我也不认为一般有封闭形式(您可能想去 mathoverflow 讨论:))。

【讨论】:

    【解决方案3】:

    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();
    }
    

    【讨论】:

      【解决方案4】:

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

      例如,您可以使用一些代数证明如果 f 由 f(x)=(ax+1)(-x+d) 定义,其中 a^2=d^2=1 和 a+d0那么对于所有实数 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) = (2/(1-x))/(2x/(1-x))=1/x 取消 (1-x)。

      这不适用于 x=1 或 x=0,除非我们允许定义满足 1/inf = 0、1/0 = inf 的“无限”值。

      【讨论】:

      • 实际上是一个非常好的尝试。但是,我得到 f(f(x)) = -1/x 不幸的是,求解一些正确的 a,b,c,d 总是给出一些复杂的值。
      • 正确 - 抱歉!应该已经意识到,因为这些变换的组合是 2x2 矩阵的矩阵乘法,因此 f(f(x))=1/x 意味着存在 2x2 实矩阵 A st A^2 = {{0,1},{1 ,0}} 取行列式(det A)^2 = -1,所以没有真正的解决方案!
      【解决方案5】:

      好吧,这里是 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

      那么,你可以这样定义g:

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

      这很有效

      • ∀ a ∈ A, g(g(a)) = g(σ(f(a)). 由(3), f(a) ∈ A 所以 σ(f(a)) ∈ B 所以 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 sup>(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 问题 - 那里接受的解决方案使用余数 mod 2 划分空间,使用 σ(x) = (x - 1),特别处理零情况.

      【讨论】:

      • 实际上,这很狡猾(以单线程方式:-)。
      • 是的,但是如果我执行 x = g(3.0), y = g(4.0), z = g(x), a = g(y) => z = 3.0,它仍然会下降, a = 4.0。对于多个值,我需要一个更好的数据结构。
      • 我从没想过我第一次看到一阶逻辑会在社区网站上。
      【解决方案6】:

      基于this answer,泛化版本的解决方案(作为Perl单行):

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

      应该总是翻转变量的符号(也就是状态)两次,并且应该总是只调用一次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;
      }
      

      【讨论】:

        【解决方案7】:

        对于第一部分:这个比 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)),我认为这更符合原始问题的精神,但我认为在一般情况下是不可能的
        • 一种涉及 g(g(x)) 只调用一次 f 的方法

        【讨论】:

        • 很好的解决方案 - 值得注意的是它当然不适用于 0 ;)
        • 使用符号存储状态的好主意。警告(不适用于 0)是通用的,此处无需提及。
        • 如果你把 0 传递给这个函数,你会得到一个除以 0 的错误。我认为值得一提。
        • 您始终可以将 +0 和 -0 作为特殊情况处理。两者都存在于双精度标准中,只是在 C 中很难区分。将 +0 映射到 -inf,将 -0 映射到 +inf。
        • 实际上,这不会给出除以零的错误,至少在 C/C++/Java 中不会。它会给出inf,这是正确的答案。 -0.0f 失败,因为它被认为等于 0。它使用 -inf 作为输入,但对于 +inf 失败。如果您将条件更改为“x > 0 || x 是 +0.0f(但不是 -0.0f!)”,它会起作用,但是我不知道如何实际编写它。 :-(
        【解决方案8】:

        其他解决方案暗示需要额外的状态。这是一个更数学的理由:

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

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

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

        因此存在复数的解决方案。我不知道是否有一个严格遵守实数的通用解决方案。

        【讨论】:

          【解决方案9】:

          同样,它被指定为 32 位数字。让 return 有更多的位,用它们在调用之间携带你的状态信息。

          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 位。

          【讨论】:

            【解决方案10】:

            我喜欢早期线程中的 javascript/lambda 建议:

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

            【讨论】:

            • 我认为这是一个优雅的解决方案。我想知道是否有任何数学/语言大师可以告诉我们一个神奇的算法来分解这样的函数。
            • 这真的有效吗?它似乎取决于语言的评估规则。通常,我会假设所有参数都首先被评估,并且只有它们的返回值传递给外部函数调用。
            • Svante:内部 f(x) 调用的返回值是一个函数。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-04-16
            • 1970-01-01
            • 1970-01-01
            • 2021-03-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多