如何找到 2 的 n 次方。 n 范围从 0 到 200
Posted
技术标签:
【中文标题】如何找到 2 的 n 次方。 n 范围从 0 到 200【英文标题】:how to find 2 to the power of n . n ranges from 0 to 200 【发布时间】:2010-05-04 05:59:57 【问题描述】:假设我的系统是 32 位机器。考虑到这一点,如果我对 n>63 使用 long int,我的值为 0。如何解决?
【问题讨论】:
你想用这些值做什么? 计算 2^n 从 0 到 200 的幂 ;) 为什么要标记操作系统? 大数字不适合长整数。您将需要更大的数据类型。 您可以对照wolframalpha.com/input/?i=2^99 验证您的结果(根据需要替换) 【参考方案1】:double
完全能够存储 2 到 1023 的幂正好。不要让别人告诉你浮点数总是不精确的。这是他们不是的特殊情况!
double x = 1.0;
for (int n = 0; n <= 200; ++n)
printf("2^%d = %.0f\n", n, x);
x *= 2.0;
程序的一些输出:
2^0 = 1
2^1 = 2
2^2 = 4
2^3 = 8
2^4 = 16
...
2^196 = 100433627766186892221372630771322662657637687111424552206336
2^197 = 200867255532373784442745261542645325315275374222849104412672
2^198 = 401734511064747568885490523085290650630550748445698208825344
2^199 = 803469022129495137770981046170581301261101496891396417650688
2^200 = 1606938044258990275541962092341162602522202993782792835301376
【讨论】:
你是怎么想到这个的?其他人是怎么得到这么多票的?? 好吧,我的解决方案在大多数其他基础上都失效了,所以在这方面,它绝对不如其他发布的解决方案。此外,许多人害怕浮点数,因为他们不了解其内部表示。 伟大的收获,FredOverflow。因为我们只需要最重要的位和它后面的零个数,double
在这里完美地工作。
虽然数字的内部存储是完整和准确的,但我认为转换为十进制进行打印不能保证准确。你很幸运。
IEEE 754-1985 §5.6:“当整数……超出范围……双精度为 10^17 时,实现者可以根据自己的选择,将……第十七位……之后的所有有效数字更改为其他十进制数字,通常为 0。” 但是这并不能阻止您实现自己的完美精确的十进制打印机,假设字符串转换甚至与问题相关。 (不过,这将是一个完整的循环,即寻找权力。)【参考方案2】:
等待 256 位编译器,然后使用 int
:-)
不,说真的,因为您只想从 1 开始并不断加倍,所以最好的办法是获得像 GNU MP 这样的大型整数库。
您可以使用如下代码(未经测试):
#include <stdio.h>
#include "gmp.h"
int main (void)
int i;
mpz_t num;
mpz_init_set_ui (num, 1);
for (i = 0; i <= 200; i++)
printf ("2^%d = ", i);
mpz_out_str (NULL, 10, num);
printf ("\n");
mpz_mul_ui (num, num, 2);
return 0;
您可以编写自己的 long 数组的数据结构,只需两个操作,double 和 print,但我认为只使用 GMP 会容易得多。
如果你确实想自己动手,看看这个。这是我过去开发的一些大型整数库的变体/简化:
#include <stdio.h>
#include <stdlib.h>
// Use 16-bit integer for maximum portability. You could adjust
// these values for larger (or smaller) data types. SZ is the
// number of segments in a number, ROLLOVER is the maximum
// value of a segment plus one (need to be less than the
// maximum value of your datatype divided by two. WIDTH is
// the width for printing (number of "0" characters in
// ROLLOVER).
#define SZ 20
#define ROLLOVER 10000
#define WIDTH 4
typedef struct
int data[SZ];
tNum;
// Create a number based on an integer. It allocates the segments
// then initialises all to zero except the last - that one is
// set to the passed-in integer.
static tNum *tNumCreate (int val)
int i;
tNum *num = malloc (sizeof (tNum));
if (num == NULL)
printf ("MEMORY ERROR\n");
exit (1);
for (i = 0; i < SZ - 1; i++)
num->data[i] = 0;
num->data[SZ-1] = val;
// Destroy the number. Simple free operation.
static void tNumDestroy (tNum *num)
free (num);
// Print the number. Ignores segments until the first non-zero
// one then prints it normally. All following segments are
// padded with zeros on the left to ensure number is correct.
// If no segments were printed, the number is zero so we just
// output "0". Then, no matter what, we output newline.
static void tNumPrint (tNum *num)
int i, first;
for (first = 1, i = 0; i < SZ; i++)
if (first)
if (num->data[i] != 0)
printf ("%d", num->data[i]);
first = 0;
else
printf ("%0*d", WIDTH, num->data[i]);
if (first)
printf ("0");
printf ("\n");
// Double a number. Simplified form of add with carry. Carry is
// initialised to zero then we work with the segments from right
// to left. We double each one and add the current carry. If
// there's overflow, we adjust for it and set carry to 1, else
// carry is set to 0. If there's carry at the end, then we have
// arithmetic overflow.
static void tNumDouble (tNum *num)
int i, carry;
for (carry = 0, i = SZ - 1; i >= 0; i--)
num->data[i] = num->data[i] * 2 + carry;
if (num->data[i] >= ROLLOVER)
num->data[i] -= ROLLOVER;
carry = 1;
else
carry = 0;
if (carry == 1)
printf ("OVERFLOW ERROR\n");
exit (1);
// Test program to output all powers of 2^n where n is in
// the range 0 to 200 inclusive.
int main (void)
int i;
tNum *num = tNumCreate (1);
printf ("2^ 0 = ");
tNumPrint (num);
for (i = 1; i <= 200; i++)
tNumDouble (num);
printf ("2^%3d = ", i);
tNumPrint (num);
tNumDestroy (num);
return 0;
及其相关输出:
2^ 0 = 1
2^ 1 = 2
2^ 2 = 4
2^ 3 = 8
2^ 4 = 16
2^ 5 = 32
2^ 6 = 64
2^ 7 = 128
2^ 8 = 256
2^ 9 = 512
: : : : :
2^191 = 3138550867693340381917894711603833208051177722232017256448
2^192 = 6277101735386680763835789423207666416102355444464034512896
2^193 = 12554203470773361527671578846415332832204710888928069025792
2^194 = 25108406941546723055343157692830665664409421777856138051584
2^195 = 50216813883093446110686315385661331328818843555712276103168
2^196 = 100433627766186892221372630771322662657637687111424552206336
2^197 = 200867255532373784442745261542645325315275374222849104412672
2^198 = 401734511064747568885490523085290650630550748445698208825344
2^199 = 803469022129495137770981046170581301261101496891396417650688
2^200 = 1606938044258990275541962092341162602522202993782792835301376
【讨论】:
如果我想使用自己的数据结构,程序是什么> @mousey:这真的取决于你的数据结构。提出一个数据结构,你可能会得到一些建议。 @mousey:使用String
查看我的解决方案。【参考方案3】:
python 支持开箱即用的大整数。在任何 linux 提示符下运行:
$ python -c "for power in range(201): print power, 2**power"
0 1
1 2
2 4
3 8
4 16
5 32
6 64
<snip>
196 100433627766186892221372630771322662657637687111424552206336
197 200867255532373784442745261542645325315275374222849104412672
198 401734511064747568885490523085290650630550748445698208825344
199 803469022129495137770981046170581301261101496891396417650688
200 1606938044258990275541962092341162602522202993782792835301376
如有必要,这可以很容易地制作成脚本。查看任何 python 教程。
【讨论】:
@Thorarin:我没有在问题中看到任何特定于语言的内容。我现在才看到带有 C/C++/Java 的标签,但这意味着他不太关心使用哪种语言。可能是我推断的太多了……【参考方案4】:自从我认真使用 Java 已经很久了,但是:BigInteger 类?它具有所有常用的数学(multiply
、pow
)和按位(shiftLeft
)运算。
您的标记有点令人困惑,您更喜欢哪种语言?
【讨论】:
+1 使用 BigInteger 只需一行代码:java.sun.com/j2se/1.4.2/docs/api/java/math/…pow
是不需要的; shiftLeft
就足够了。看我的回答。【参考方案5】:
使用java.math.BigInteger.shiftLeft
。
for (int i = 0; i <= 200; i++)
System.out.format("%d = %s%n", i, BigInteger.ONE.shiftLeft(i));
摘自output:
0 = 1
1 = 2
2 = 4
3 = 8
4 = 16
:
197 = 200867255532373784442745261542645325315275374222849104412672
198 = 401734511064747568885490523085290650630550748445698208825344
199 = 803469022129495137770981046170581301261101496891396417650688
200 = 1606938044258990275541962092341162602522202993782792835301376
如果BigInteger
不可用,您也可以手动进行乘法并将其存储在String
中。
String s = "1";
for (int i = 0; i < 200; i++)
StringBuilder sb = new StringBuilder();
int carry = 0;
for (char ch : s.toCharArray())
int d = Character.digit(ch, 10) * 2 + carry;
sb.append(d % 10);
carry = d / 10;
if (carry != 0) sb.append(carry);
s = sb.toString();
System.out.format("%d = %s%n", i + 1, sb.reverse());
(see full output)
【讨论】:
不是在每次迭代中左移BigInteger.ONE
'i' 次,而是从 BigInteger.ONE
的副本开始并在每次迭代中左移一次更有效?
@Angry:我想要简洁和可读性而不是效率,但我认为BigInteger
移位1
位k
次实际上可能比移位k-1
位便宜(大多数其中为零)1
时间。
你的方式肯定更简洁。感谢您指出在这种情况下它也更有效。 +1 :)
@Angry:不要只相信我的话——看看基准! ideone.com/wIRln【参考方案6】:
在 C/C++ 中,我不知道存储这么大整数的标准方法,pax 的解决方案是正确的方法。
但是对于 Java,你确实有出路,BigInteger
【讨论】:
【参考方案7】:使用方案!
1 => (expt 2 200)
1606938044258990275541962092341162602522202993782792835301376
【讨论】:
【参考方案8】:如果unsigned long int
是 64 位,那么您可以表示的 2^n 的最大值是 2^63(即 n = 63):
unsigned long int x = (1UL << n); // n = 0..63
【讨论】:
使用我们可以表示更多的字符串或数组。 我相信这就是你所需要的:***.com/questions/2643487/… :-)【参考方案9】:在科特林中:
var x= readLine()!!.toInt()
var y=BigDecimal(1)
for (i in 1..x)
y *= BigDecimal(2)
println(DecimalFormat().format(y))
【讨论】:
欢迎来到 ***。请解释您的解决方案。以上是关于如何找到 2 的 n 次方。 n 范围从 0 到 200的主要内容,如果未能解决你的问题,请参考以下文章