Answers:
怎么样:
f(n)=符号(n)-(-1)n * n
在Python中:
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)
Python自动将整数提升为任意长度的long。在其他语言中,最大的正整数将溢出,因此它将适用于除那个整数以外的所有整数。
为了使之成为真正的数字工作,你需要更换ñ在(-1)ñ用{ ceiling(n) if n>0; floor(n) if n<0 }
。
在C#中(除了在溢出情况下,任何double都适用):
static double F(double n)
{
if (n == 0) return 0;
if (n < 0)
return ((long)Math.Ceiling(n) % 2 == 0) ? (n + 1) : (-1 * (n - 1));
else
return ((long)Math.Floor(n) % 2 == 0) ? (n - 1) : (-1 * (n + 1));
}
您没有说他们期望使用哪种语言...这是一个静态解决方案(Haskell)。基本上搞乱了两个最高有效位:
f :: Int -> Int
f x | (testBit x 30 /= testBit x 31) = negate $ complementBit x 30
| otherwise = complementBit x 30
在动态语言(Python)中,这要容易得多。只需检查参数是否为数字X并返回返回-X的lambda:
def f(x):
if isinstance(x,int):
return (lambda: -x)
else:
return x()
class C a b | a->b where { f :: a->b }
; instance C Int (()->Int) where { f=const.negate }
; instance C (()->Int) Int where { f=($()) }
。
这证明了为什么这样的函数如果不使用额外的信息(32位的int除外),对于所有数字都不存在:
我们必须使f(0)=0。(证明:假设f(0)= x。然后f(x)= f(f(0))= -0 =0。现在,-x = f(f(x ))= f(0)= x,这意味着x =0。)
此外,对于任何x
和y
,假设f(x) = y
。那我们要f(y) = -x
。和f(f(y)) = -y => f(-x) = -y
。总结一下:如果f(x) = y
,则f(-x) = -y
和f(y) = -x
,和f(-y) = x
。
因此,我们需要将除0以外的所有整数划分为4组,但此类整数的数量为奇数;不仅如此,如果我们删除没有正整数的整数,我们仍然有2(mod4)个数字。
如果我们删除剩下的2个最大数(按abs值),则可以获得函数:
int sign(int n)
{
if(n>0)
return 1;
else
return -1;
}
int f(int n)
{
if(n==0) return 0;
switch(abs(n)%2)
{
case 1:
return sign(n)*(abs(n)+1);
case 0:
return -sign(n)*(abs(n)-1);
}
}
当然,另一种选择是不遵从0,并获得我们删除的2个数字作为奖励。(但这真是愚蠢。)
n = -2147483648
(最小值);abs(n)
在这种情况下,您将无法做到,结果将是不确定的(或例外)。
感谢C ++中的重载:
double f(int var)
{
return double(var);
}
int f(double var)
{
return -int(var);
}
int main(){
int n(42);
std::cout<<f(f(n));
}
或者,您可以滥用预处理器:
#define f(n) (f##n)
#define ff(n) -n
int main()
{
int n = -42;
cout << "f(f(" << n << ")) = " << f(f(n)) << endl;
}
所有负数都是这样。
f(n)=绝对值(n)
由于补码整数的负数比正数多,f(n) = abs(n)
因此比f(n) = n > 0 ? -n : n
与相同的解在多一种情况下有效f(n) = -abs(n)
。让你一个...:D
更新
不,它在一种情况下是无效的,因为我刚刚被litb的评论所认可... abs(Int.Min)
只会溢出...
我也考虑过使用mod 2信息,但得出的结论是,它直到早期都行不通。如果操作正确,它将适用于所有数字,除非Int.Min
会溢出。
更新
我玩了一段时间,寻找了一个不错的操作技巧,但是当mod 2解决方案合而为一时,我找不到一个好的单线。
f(n)= 2n(绝对(n)%2)-n + sgn(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
并将计算包括在unchecked
块中。然后,您甚至Int.Min
可以像未经检查的否定一样映射到自身。
更新
受到另一个答案的启发,我将解释该功能的工作原理以及如何构建这样的功能。
让我们从头开始。将该函数f
重复应用于给定值,n
产生一系列值。
n => f(n)=> f(f(n))=> f(f(f(n())))=> f(f(f(f(n))))=> ...
问题要求f(f(n)) = -n
,即f
否定论证是两个连续的应用。的另外两个应用程序(f
总共四个)再次使该论点无效n
。
n => f(n)=> -n => f(f(f(n())))=> n => f(n)=> ...
现在有一个明显的长度为4的循环。代入x = f(n)
并注意所获得的方程式f(f(f(n))) = f(f(x)) = -x
成立,得出以下结果。
n => x => -n => -x => n => ...
因此,我们得到了一个长度为4的循环,其中包含两个数字,而两个数字为负。如果将循环想象为矩形,则取反的值位于相对的角上。
构造这样一个循环的许多解决方案之一是从n开始。
n =>求反,然后减去1 -n-1 =-(n + 1)=>加一 -n =>取反并加一个 n + 1 =>减一 ñ
这样一个周期的一个具体例子是+1 => -2 => -1 => +2 => +1
。我们快完成了。注意构造的循环包含一个奇数正数,其偶数个后继数,并且两个数都取反,我们可以轻松地将整数划分为许多这样的循环(2^32
是4的倍数),并找到了满足条件的函数。
但是我们有一个零问题。循环必须包含,0 => x => 0
因为零取反。并且因为周期已经说明了,0 => x
所以它随之而来0 => x => 0 => x
。这只是一个长度为2的循环,x
在两次应用后变为,而不是-x
。幸运的是,有一种情况可以解决问题。如果X
等于零,我们得到一个长度为1的循环,该循环仅包含零,并且解决了这个问题,得出的结论是零是的固定点f
。
做完了吗 几乎。我们有2^32
数字,零是不动点,剩下2^32 - 1
数字,我们必须将该数字划分为四个数字的循环。不好,2^32 - 1
它不是四的倍数-在任何长度为四的循环中都将保留三个数字。
我将使用范围从-4
到的较小的3位带符号iteger集来解释解决方案的其余部分+3
。我们完成了零。我们有一个完整的周期+1 => -2 => -1 => +2 => +1
。现在让我们构造从开始的循环+3
。
+3 => -4 => -3 => +4 => +3
出现的问题+4
是不能表示为3位整数。我们将+4
取反-3
,即+3
-仍然是有效的3位整数-,然后将其加到+3
(binary 011
)将产生100
二进制。解释为无符号整数,+4
但是我们必须将其解释为有符号整数-4
。因此,实际上-4
对于此示例或Int.MinValue
一般情况,是整数算术求反的第二个固定点- 0
并Int.MinValue
映射到它们自己。因此,周期实际上如下。
+3 => -4 => -3 => -4 => -3
这是长度为2 +3
的循环,另外通过进入循环-4
。其结果是-4
经过两个功能应用正确映射到自身,+3
正确映射到-3
经过两次的功能应用,但-3
经过两级功能的应用被错误地映射到自身。
因此,我们构造了一个功能,该功能适用于除一个整数之外的所有整数。我们可以做得更好吗?不,我们不可以。为什么?我们必须构造长度为4的循环,并且能够覆盖整个整数范围(最多四个值)。剩余值是两个固定点0
和Int.MinValue
必须被映射到自身和两个任意的整数x
,并-x
必须由两个功能的应用程序被映射到彼此。
为了映射x
,-x
反之亦然,它们必须形成四个周期,并且必须位于该周期的相对角。结果0
,Int.MinValue
也必须处于相反的角落。这将正确映射x
并-x
交换两个固定点,0
并Int.MinValue
在两个函数应用程序之后进行交换,并为我们提供两个失败的输入。因此,不可能构造一个适用于所有值的函数,但是我们拥有一个适用于除一个值之外的所有值的函数,这是我们可以实现的最佳结果。
使用复数,可以有效地将数字取负的任务分为两个步骤:
很棒的是,您不需要任何特殊的处理代码。乘以我就可以了。
但是您不可以使用复数。因此,您必须使用部分数据范围以某种方式创建自己的虚轴。由于您需要的假想(中间)值与初始值一样多,因此只剩下一半的数据范围。
我假设下一个带符号的8位数据,试图在下图上形象化。您必须将其缩放为32位整数。初始n的允许范围是-64至+63。这是函数对正数n的作用:
对于负数n,该函数使用中间范围-65 ..- 128。
float
vs int
)。许多答案描述的“ 4元环”需要4个状态,可以将其表示为2维,每个维具有2个状态。这个答案的问题是,它需要额外的处理空间(对于-64..63仅“有效”,但需要-128..127的空间),并且没有明确说明书写的公式!
除int.MaxValue和int.MinValue以外的作品
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));
}
0
至” 0
和“ -2147483648
至” 。对于其余数字,请遵循上图中的箭头。从SurDin的答案及其评论中可以明显看出,在这种情况下将有两个数字,并且没有其他可交换的数字。-2147483648
x => -x
2147483647
-2147483647
问题没有说明该函数的输入类型和返回值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
为true。
显然,这种方法可以扩展到适用于更大范围的数字...
对于javascript(或其他动态类型的语言),您可以让函数接受一个int或一个对象,然后返回另一个。即
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;
}
根据您的平台,某些语言可以使您保持功能状态。VB.Net,例如:
Function f(ByVal n As Integer) As Integer
Static flag As Integer = -1
flag *= -1
Return n * flag
End Function
IIRC,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),但它的效果比迄今为止建议的任何其他功能都要好得多。
利用JavaScript异常。
function f(n) {
try {
return n();
}
catch(e) {
return function() { return -n; };
}
}
f(f(0)) => 0
f(f(1)) => -1
对于所有32位值(警告为-0为-2147483648)
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);
}
基本上,您需要将每个-x => x => -x循环与ay => -y => y循环配对。所以我将球拍的两侧配对了split
。
例如对于4位整数:
0 => 7 => -8 => -7 => 0
1 => 6 => -1 => -6 => 1
2 => 5 => -2 => -5 => 2
3 => 4 => -3 => -4 => 3
一个C ++版本,可能会稍微改变规则,但适用于所有数字类型(浮点数,整数,双精度数),甚至是使一元负号过载的类类型:
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;
}
x86 asm(AT&T风格):
; 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
检查代码,传递所有可能的32位整数,错误-2147483647(下溢)。
使用全局变量...但是是这样吗?
bool done = false
f(int n)
{
int out = n;
if(!done)
{
out = n * -1;
done = true;
}
return out;
}
该Perl解决方案适用于整数,浮点数和字符串。
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
n
是一个字符串,我可以使548变成“ First_Time_548”,然后在下一次运行该函数时... if(prefix == First_Time_“)用”-“替换” First_Time_“
我实际上并没有在尝试解决问题本身,但是确实有一些评论,因为问题指出这个问题是(工作?)面试的一部分:
int.MinValue
到int.MaxValue
,然后n
对该范围调用中的每个循环进行循环,f(f(n))
并检查结果为-n
),然后告诉我将使用“测试驱动开发”来获得此功能。哦,此答案假设面试是针对C#编程相关职位的。如果面试是针对与数学相关的职位,那当然是一个愚蠢的答案。;-)
我会更改2个最高有效位。
00.... => 01.... => 10.....
01.... => 10.... => 11.....
10.... => 11.... => 00.....
11.... => 00.... => 01.....
如您所见,它只是一个附加项,省去了进位。
我是怎么得到答案的?我的第一个想法只是对称性的需要。4转回到我的起点。起初我以为是2位格雷码。然后我认为实际上标准二进制就足够了。
这是受要求启发的解决方案,或声称不能使用复数来解决此问题。
乘以-1的平方根是一个想法,这似乎只是失败了,因为-1在整数上没有平方根。但是,使用诸如mathematica之类的程序可以得出以下等式
(1849436465 2 +1)mod(2 32 -3)= 0。
这几乎与平方根为-1一样好。函数的结果必须是有符号整数。因此,我将使用修改后的模运算mods(x,n),它返回与最接近0的x模n一致的整数y。只有很少的编程语言具有suc模运算,但可以轻松定义。例如在python中,它是:
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)
这满足f(f(x)) = -x
范围内的所有整数。的结果也在此范围内,但当然计算将需要64位整数。[-2
31
-2, 2
31
-2]
f(x)
C#的范围为2 ^ 32-1个数字,除(Int32.MinValue)以外的所有int32数字
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
本质上,该函数必须将可用范围划分为大小为4的循环,其中-n在n循环的另一端。但是,0必须是大小为1的循环的一部分,否则为0->x->0->x != -x
。由于单独存在0,因此在我们的范围内必须有3个其他值(其大小是4的倍数),而不是在4个元素的适当循环中。
我选择了这些额外的怪异值是MIN_INT
,MAX_INT
和MIN_INT+1
。此外,MIN_INT+1
将MAX_INT
正确映射,但会卡在此处而不重新映射。我认为这是最好的折衷方案,因为它具有仅极限值无法正常工作的良好特性。而且,这意味着它将对所有 BigInts 都适用。
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)
没有人说它必须是无国籍的。
int32 f(int32 x) {
static bool idempotent = false;
if (!idempotent) {
idempotent = true;
return -x;
} else {
return x;
}
}
作弊,但没有很多例子。更加邪恶的是偷看堆栈以查看调用方的地址是否为&f,但这将更具可移植性(尽管不是线程安全的……线程安全版本将使用TLS)。更邪恶的是:
int32 f (int32 x) {
static int32 answer = -x;
return answer;
}
当然,对于MIN_INT32而言,这两种方法都无法很好地发挥作用,但是除非允许您返回更广泛的类型,否则您几乎无能为力。
我可以想象将第31位用作假想(i)位将是支持整个范围一半的方法。
问题指出“ 32位有符号整数”,但没有指定它们是二进制补码还是二进制补码。
如果您使用1补码,则所有2 ^ 32值都将以长度为4的周期出现-您不需要为零的特殊情况,也不需要条件。
在C中:
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)
作为数学家,我想就这个有趣的问题分享我的观点。我认为我有最有效的解决方案。
如果我没记错的话,只需翻转第一位就可以对一个有符号的32位整数求反。例如,如果n = 1001 1101 1110 1011 1110 0000 1110 1010,则-n = 0001 1101 1110 1011 1110 0000 1110 1010。
那么,我们如何定义一个函数f,该函数采用一个带符号的32位整数并返回另一个带符号的32位整数,并且该属性取f两次与翻转第一位相同?
让我改写这个问题,而不必提及整数等算术概念。
我们如何定义一个函数f,该函数接受一个零序列和一个长度为32的序列,并返回一个零序列和一个长度相同的序列,而属性f取两次与翻转第一位相同?
观察:如果您可以回答32位大小写的上述问题,那么您也可以回答64位大小写,100位大小写等。您只需将f应用于前32位。
现在,如果您可以回答2位大小写的问题,瞧!
是的,事实证明,更改前2位就足够了。
这是伪代码
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.
备注:步骤2和步骤3可以合计为(a,b)->(-b,a)。看起来很熟悉?那应该使您想起平面旋转90度以及乘以-1的平方根的情况。
如果我只是单独提供伪代码而没有冗长的前奏,那似乎就像是一只兔子,我想解释一下我是如何得到解决方案的。