【问题标题】:Finding a nonzero integer x where x == -x?找到一个非零整数 x 其中 x == -x?
【发布时间】:2013-11-03 18:43:21
【问题描述】:

在我大学的算法和数据结构课程中,我收到了这个问题:

哪个整数的位模式与他的负值相同?

表示:x == -x

我知道 0 有效,但我怀疑讲师正在寻找其他数字 x。 x是什么?你会怎么找到它?

【问题讨论】:

  • 1111111111111111 呢?
  • 想想 2 的补码如何在极端情况下发挥作用
  • @LuiggiMendoza:这是-1,但如果我理解正确的话,你不能以其他方式显示它。 :)
  • Java 没有无符号整数,因此 0 是唯一的解决方案。例如,在 C 中,您可以将相同的位模式解释为有符号或无符号整数。
  • @lbalazscs 不需要无符号整数。这个谜题需要一个 2 的补码有符号整数,其不对称范围约为 0。具体来说,它们的负值比正值多一个。

标签: java math int discrete-mathematics


【解决方案1】:

Integer.MIN_VALUE 和 Long.MIN_VALUE 没有等效的正值,当你取它们的负值时,你会得到相同的值。

负数与翻转所有位并加一相同。即

-x = ~x + 1

所以 -0x80000000 = 0x7fffffff + 1 = 0x8000000

注意:Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE 是负数。此方法的 javadoc 中对此进行了概述。

技术上有很多答案和类型

byte x = 0;
short x = 0;
char x = 0;
int x = 0;
int x = Integer.MIN_VALUE;
float x = 0.0f;
float x = -0.0f;
long x = 0;
long x = Long.MIN_VALUE;
double x = 0.0;
double x = -0.0;
Byte x = 0;
Short x = 0;
Character x = 0;
Integer x = 0;
Integer x = Integer.MIN_VALUE;
Float x = 0.0f;
Float x = -0.0f;
Long x = 0L;
Long x = Long.MIN_VALUE;
Double x = 0.0;
Double x = -0.0;

类似的 Java Puzzler 是;以下表达式何时是 true

x != x + 0

编辑:浮点同时具有+0.0-0.0。你可能会认为-0.00.0 的值不同,尽管-0.0 == -(-0.0) 是这种情况

注意:Double.compare(0.0, -0.0) > 0 注意:

【讨论】:

  • @jmiserez 获取有关数据结构的课程,您不应该与特定的编程语言内部相关。
  • 所以本质上你是说这是一个有技巧的问题?
  • @jmiserez 好吧,如果你想成为技术专家,0 也不是答案,因为它不是负值。
  • @jmiserez int x = Integer.MIN_VALUE; if (x != 0 && x == -x) 是真的。
  • 我在您的解决方案中看不到的内容:如果我否定 x 并添加 +1,那么它不是同一个数字。据我了解他的问题,这不应该是重点。 “是否有一个现有的整数,即 x == -x?”这是整个问题,在我看来,按照我的理解,这个问题没有意义。但我认为这个解决方案是他想要我们提供的。非常感谢! :)
【解决方案2】:

假设您采用带符号二进制补码格式的最小可表示数字。例如,假设这个数字(称为 x)具有位模式 100000...0。要计算 -x,首先翻转所有位以得到 01111...1,然后将其加一。这会导致较大的波纹进位,再次导致数字1000....0,这是您开始使用的数字。因此,您将拥有x == -x。对于 Java 整数,此值为 Integer.MIN_VALUE,即 -231

您实际上可以用数学方法计算出来。由于带符号二进制补码格式的所有数字都表示为模 2 的某个幂(例如,2d),因此语句

x == -x

真正的意思

x == -x (mod 2d)

这意味着

2x == 0 (mod 2d)

因此,这个问题的解决方案是所有数字 x 的集合,其中 2x 是 0 mod 2d。这些是任何整数 k 的形式为 k × 2d 的数字。这些值中只有两个可以用 d + 1 位的有符号二进制补码格式表示,即 0 和 -2d。因此,最小可能的负数总是比较等于它的负值。

希望这会有所帮助!

【讨论】:

  • +1 表示不会忘记 0(尽管这在考虑 x==-x 时应该很明显)
  • 我不明白x == -x (mod 2^d) 怎么能转到2x == 0 (mod 2^d),因为-x 是乘法,而不是加法=\
  • @LuiggiMendoza 将x 添加到等式的两边???这适用于模算术。
  • @ajb 应该是2x == -x(mod2^d) + x,不一样。
  • @LuiggiMendoza 在x == y (mod m) 中,这应该是中间的等价符号(带有三个水平破折号)而不是==。如果您对此不熟悉,请在 Wikipedia 中查找“模数运算”。 (mod m) 不是模“运算符”,就像 (x mod m) 那样。如果a==b (mod m),那么a+c == b+c (mod m)
【解决方案3】:

对于 8 位整数:1000 0000 有符号这是 -128 而无符号这是 128

【讨论】:

    【解决方案4】:

    换个角度看:所有有符号原始整数类型都表示范围内的整数

    -2N-1 到 2N-1-1

    (含),其中 N 是位数。每当执行任何数学整数运算时,如果数学结果是某个数字 Z 超出该范围(“溢出”),那么实际结果将是 R = Z + 2N * k,其中k 是选择的一些正整数或负整数,因此 R 将在 -2N-1 到 2N-1 - 1 的范围内。所以说 x = -2N-1,我们计算 -x。数学结果是 Z = 2N-1,但这超出了范围,因为 Z > 2N-1-1。所以为了让它在范围内,我们需要为一些 k 添加 2N * k,并且 k 必须是 -1。因此实际结果是 R = 2N-1 + (2N)*(-1) = 2N-1 - 2N = -2N-1,即x的原始值。所以这是一个使 x == -x 的值。

    Java 只有有符号整数类型,但在有无符号类型的语言中,无符号类型的范围是 0 到 2N-1,包括 0 到 2N-1。但其他一切都以同样的方式适用。

    【讨论】:

      【解决方案5】:

      如前所述,这个问题是模棱两可的。

      0 当然是显而易见的解决方案,正如其他人所讨论的那样,Java 中没有其他解决方案(这就是问题的标记方式)。

      在 C 中,对于任何有符号整数类型,给定类型的最小值可能一些实现的解决方案。例如,给定一个 2 的补码表示,评估 -INT_MIN可能得到 -INT_MIN。但事实上,由于溢出,评估该表达式的行为是 undefined,即使您假设 2 的补码。 (环绕语义很常见,但不能保证。)此外,C 标准不需要 2 的补码表示;它还允许 1's-complement 和 sign-and-magnitude,它们都没有额外的负值。

      这个程序:

      #include <stdio.h>
      #include <limits.h>
      int main(void) {
          int n = INT_MIN;
          printf("%d\n%d\n", n, -n); /* Warning: Undefined behavior for -n */
      }
      

      在我的系统上产生这个输出:

      -2147483648
      -2147483648
      

      对 C 无符号类型的操作具有更严格定义的行为。这个程序:

      #include <stdio.h>
      #include <limits.h>
      int main(void) {
          unsigned int n = UINT_MAX / 2 + 1;
          printf("%u\n%u\n", n, -n);
      }
      

      在具有 32 位 int(且无填充位)的系统上提供此输出:

      2147483648
      2147483648
      

      并将在任何符合要求的实现上打印两行相同的输出。

      C++ 在这方面与 C 有相同的行为(或未定义的行为)。

      在 Perl 中,如果一个大整数太大而无法表示为整数,那么它会落入浮点表示形式——但是 Perl 标量很复杂,并且可以同时存储多个表示形式。在我的 64 位系统上,这个 Perl 程序:

      #!/usr/bin/perl
      
      use strict;
      use warnings;
      
      my $n = -2.0**63;
      print $n, "\n", -$n, "\n";
      printf "%d\n%d\n", $n, -$n;
      

      给出这个输出:

      -9.22337203685478e+18
      9.22337203685478e+18
      -9223372036854775808
      -9223372036854775808
      

      我不完全确定自己能解释清楚。

      Python 似乎回退到某种形式的扩展精度整数,因此不会出现溢出问题,因此没有数值是它自己的否定。许多其他语言(包括,我认为,大多数 Lisp 方言)做同样的事情。

      在 Ada 中,整数溢出没有未定义的行为;它需要引发异常。这个程序:

      with Ada.Text_IO; use Ada.Text_IO;
      procedure Foo is
          N: Integer := Integer'First;
      begin
          Put_Line(Integer'Image(N));
          Put_Line(Integer'Image(-N));
      end Foo;
      

      只产生一行输出:

      -2147483648
      

      然后死于 Constraint_Error 异常。

      等等,等等,然后……

      因此,除非讲师只是在寻找零作为答案,否则它在很大程度上取决于上下文。

      看看这个问题,你为什么认为0(这是对所写问题的一个完全正确和明显的答案,显然是 Java 中唯一正确的答案)不是教师正在寻找的为了?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-04-11
        相关资源
        最近更新 更多