Math 设计函数f(f(n))=-n

Math 设计函数f(f(n))=-n,math,integer,Math,Integer,我在上次面试中遇到的一个问题: 设计功能f,以便: f(f(n)) == -n 其中n是32位有符号整数;你不能使用复数算术 如果你不能为整个数字范围设计这样一个函数,那么就尽可能为最大范围设计它 有什么想法吗?这适用于所有负数 f(n) = abs(n) 在C#中,这变成以下内容: public static Int32 f(Int32 n) { return 2 * n * (Math.Abs(n) % 2) - n + Math.Sign(n); } 要使其适用于所有值,必须将

我在上次面试中遇到的一个问题:

设计功能
f
,以便:

f(f(n)) == -n
其中
n
是32位有符号整数;你不能使用复数算术

如果你不能为整个数字范围设计这样一个函数,那么就尽可能为最大范围设计它


有什么想法吗?

这适用于所有负数

f(n) = abs(n) 在C#中,这变成以下内容:

public static Int32 f(Int32 n)
{
    return 2 * n * (Math.Abs(n) % 2) - n + Math.Sign(n);
}
要使其适用于所有值,必须将
Math.Abs()
替换为
(n>0)+n:-n
并将计算包含在未选中的
块中。然后,您甚至可以像未检查的否定一样将
Int.Min
映射到自身

更新

受另一个答案的启发,我将解释函数是如何工作的,以及如何构造这样一个函数

让我们从头开始。函数
f
重复应用于给定值
n
,产生一系列值

n => f(n) => f(f(n)) => f(f(f(n))) => f(f(f(f(n)))) => ... 现在有一个明显的周期长度为4。替换
x=f(n)
并注意到获得的方程
f(f(f(n))=f(f(x))=-x成立,得到以下结果

n => x => -n => -x => n => ... 出现的问题是
+4
不能表示为3位整数。我们可以通过将
-3
+3
求反来获得
+4
——这仍然是一个有效的3位整数——但随后将一个与
+3
(二进制
011
)相加,得到
100
二进制。解释为无符号整数它是
+4
,但我们必须解释为有符号整数
-4
。因此实际上,在这个例子中,
-4
或者在一般情况下,
Int.MinValue
是整数算术求反的第二个固定点-
0
Int.MinValue
被映射到它们自己。所以这个循环实际上是这样的

+3 => -4 => -3 => -4 => -3 +3 => -4 => -3 => -4 => -3 这是一个长度为2的循环,另外,
+3
通过
-4
进入循环。因此,在两次功能应用后,
-4
正确映射到自身,
+3
在两次功能应用后正确映射到
-3
,但在两次功能应用后,
-3
错误映射到自身

所以我们构造了一个函数,它适用于除一个整数以外的所有整数。我们能做得更好吗?不,我们不能。为什么?我们必须构造长度为4的循环,并且能够覆盖多达4个值的整个整数范围。其余值是必须映射到自身的两个固定点
0
Int.MinValue
,以及必须通过两个函数应用程序相互映射的两个任意整数
x
-x


要将
x
映射到
-x
,反之亦然,它们必须形成一个四个循环,并且必须位于该循环的相对角。因此,
0
Int.MinValue
也必须位于相反的角落。这将正确映射
x
-x
,但在两次函数应用后交换两个固定点
0
Int.MinValue
,并留下两个失败的输入。因此,不可能构造一个适用于所有值的函数,但我们有一个适用于除一个值以外的所有值的函数,这是我们所能实现的最佳功能。

根据您的平台,某些语言允许您在函数中保留状态。例如,VB.Net:

Function f(ByVal n As Integer) As Integer
    Static flag As Integer = -1
    flag *= -1

    Return n * flag
End Function
iRC+C++也允许这样做。但我怀疑他们正在寻找一个不同的解决方案

另一个想法是,由于他们没有定义第一次调用函数的结果,您可以使用奇数/均匀度来控制是否反转符号:

int f(int n)
{
   int sign = n>=0?1:-1;
   if (abs(n)%2 == 0)
      return ((abs(n)+1)*sign * -1;
   else
      return (abs(n)-1)*sign;
}

所有偶数的大小加一,所有奇数的大小减一。两次调用的结果大小相同,但一次调用的结果是偶数,我们交换符号。在某些情况下,这将不起作用(-1,max或min int),但它比目前为止建议的任何其他方法都好得多。

我可以想象,使用31位作为假想(I)位将是一种支持总范围一半的方法。

适用于n=[0..2^31-1]

int f(int n) {
  if (n & (1 << 31)) // highest bit set?
    return -(n & ~(1 << 31)); // return negative of original n
  else
    return n | (1 << 31); // return n with highest bit set
}
intf(intn){
如果(n&(1那么:

f(n) = sign(n) - (-1)n * n Python自动将整数提升到任意长度。在其他语言中,最大的正整数将溢出,因此它将适用于除该整数之外的所有整数



要使其适用于实数,您需要将n in(-1)n替换为
{ceiling(n)if n>0;floor(n)if n,但问题并没有说明函数
f
的输入类型和返回值必须是什么(至少不是您表示的方式)

…只是当n是32位整数时,
f(f(n))=-n

那么,像这样的东西怎么样

Int64 f(Int64 n)
{
    return(n > Int32.MaxValue ? 
        -(n - 4L * Int32.MaxValue):
        n + 4L * Int32.MaxValue);
}
如果n是32位整数,则语句
f(f(n))==-n
将为真


显然,这种方法可以扩展到更广泛的数字范围…

您没有说他们希望使用哪种语言…这是一个静态解决方案(Haskell)。它基本上会弄乱两个最重要的位:

f::Int->Int
f x |(testBit x 30/=testBit x 31)=对$x 30位求反
|否则=位x30
在动态语言(Python)中要容易得多。只需检查参数是否为数字X并返回返回-X的lambda:

def(x):
如果isinstance(x,int):
返回值(λ:-x)
其他:
返回x()
对于javascript(或其他动态类型语言),您可以让函数接受int或object并返回另一个

function f(n) {
    if (n.passed) {
        return -n.val;
    } else {
        return {val:n, passed:1};
    }
}
给予

js> f(f(10))  
-10
js> f(f(-10))
10
或者,您可以在强类型语言中使用重载,尽管这可能会违反规则

int f(long n) {
    return n;
}

long f(int n) {
    return -n;
}
对于所有32位值(注意-0是-21474836
def f(n): 
    if n == 0: return 0
    if n >= 0:
        if n % 2 == 1: 
            return n + 1
        else: 
            return -1 * (n - 1)
    else:
        if n % 2 == 1:
            return n - 1
        else:
            return -1 * (n + 1)
Int64 f(Int64 n)
{
    return(n > Int32.MaxValue ? 
        -(n - 4L * Int32.MaxValue):
        n + 4L * Int32.MaxValue);
}
function f(n) {
    if (n.passed) {
        return -n.val;
    } else {
        return {val:n, passed:1};
    }
}
js> f(f(10))  
-10
js> f(f(-10))
10
int f(long n) {
    return n;
}

long f(int n) {
    return -n;
}
int rotate(int x)
{
    static const int split = INT_MAX / 2 + 1;
    static const int negativeSplit = INT_MIN / 2 + 1;

    if (x == INT_MAX)
        return INT_MIN;
    if (x == INT_MIN)
        return x + 1;

    if (x >= split)
        return x + 1 - INT_MIN;
    if (x >= 0)
        return INT_MAX - x;
    if (x >= negativeSplit)
        return INT_MIN - x + 1;
    return split -(negativeSplit - x);
}
0 => 7 => -8 => -7 => 0
1 => 6 => -1 => -6 => 1
2 => 5 => -2 => -5 => 2
3 => 4 => -3 => -4 => 3
    Func<int, int> f = n =>
        n < 0
           ? (n & (1 << 30)) == (1 << 30) ? (n ^ (1 << 30)) : - (n | (1 << 30))
           : (n & (1 << 30)) == (1 << 30) ? -(n ^ (1 << 30)) : (n | (1 << 30));

    Console.WriteLine(f(f(Int32.MinValue + 1))); // -2147483648 + 1
    for (int i = -3; i <= 3  ; i++)
        Console.WriteLine(f(f(i)));
    Console.WriteLine(f(f(Int32.MaxValue))); // 2147483647
2147483647
3
2
1
0
-1
-2
-3
-2147483647
boolean inner = true;

int f(int input) {
   if(inner) {
      inner = false;
      return input;
   } else {
      inner = true;
      return -input;
   }
}
int f(int n):
    if n == 0 or n == MIN_INT or n == MAX_INT: return n
    return ((Math.abs(n) mod 2) * 2 - 1) * n + Math.sign(n)
template <class T>
struct f_result
{
  T value;
};

template <class T>
f_result <T> f (T n)
{
  f_result <T> result = {n};
  return result;
}

template <class T>
T f (f_result <T> n)
{
  return -n.value;
}

void main (void)
{
  int n = 45;
  cout << "f(f(" << n << ")) = " << f(f(n)) << endl;
  float p = 3.14f;
  cout << "f(f(" << p << ")) = " << f(f(p)) << endl;
}
bool done = false
f(int n)
{
  int out = n;
  if(!done)
  {  
      out = n * -1;
      done = true;
   }
   return out;
}
return x ^ ((x%2) ? 1 : -INT_MAX);
int32 f(int32 x) {
    static bool idempotent = false;
    if (!idempotent) {
        idempotent = true;
        return -x;
    } else {
        return x;
    }
}
int32 f (int32 x) {
    static int32 answer = -x;
    return answer;
}
1. take n, which is a signed 32-bit integer.
2. swap the first bit and the second bit.
3. flip the first bit.
4. return the result.
int32_t f(int32_t x)
{
  return (((x & 0xFFFFU) << 16) | ((x & 0xFFFF0000U) >> 16)) ^ 0xFFFFU;
}
Pass |        x
-----+-------------------
   0 | 00000001      (+1)
   1 | 0001FFFF (+131071)
   2 | FFFFFFFE      (-1)
   3 | FFFE0000 (-131071)
   4 | 00000001      (+1)

Pass |        x
-----+-------------------
   0 | 00000000      (+0)
   1 | 0000FFFF  (+65535)
   2 | FFFFFFFF      (-0)
   3 | FFFF0000  (-65535)
   4 | 00000000      (+0)
00.... => 01.... => 10.....

01.... => 10.... => 11.....

10.... => 11.... => 00.....

11.... => 00.... => 01.....
; input %edi
; output %eax
; clobbered regs: %ecx, %edx
f:
    testl   %edi, %edi
    je  .zero

    movl    %edi, %eax
    movl    $1, %ecx
    movl    %edi, %edx
    andl    $1, %eax
    addl    %eax, %eax
    subl    %eax, %ecx
    xorl    %eax, %eax
    testl   %edi, %edi
    setg    %al
    shrl    $31, %edx
    subl    %edx, %eax
    imull   %ecx, %eax
    subl    %eax, %edi
    movl    %edi, %eax
    imull   %ecx, %eax
.zero:
    xorl    %eax, %eax
    ret
sub f {
    my $n = shift;
    return ref($n) ? -$$n : \$n;
}
print $_, ' ', f(f($_)), "\n" for -2, 0, 1, 1.1, -3.3, 'foo' '-bar';
-2 2
0 0
1 -1
1.1 -1.1
-3.3 3.3
foo -foo
-bar +bar
def f(x):
    if type(x) == list:
        return -x[0]
    return [x]


f(2) => [2]
f(f(2)) => -2
def mods(x, n):
    y = x % n
    if y > n/2: y-= n
    return y
def f(x):
    return mods(x*1849436465, 2**32-3)
function f(n) {
    try {
        return n();
    }
    catch(e) { 
        return function() { return -n; };
    }
}
    public static int f(int x)
    {

        if (x == 0) return 0;

        if ((x % 2) != 0)
            return x * -1 + (-1 *x) / (Math.Abs(x));
        else
            return x - x / (Math.Abs(x));
    }