如何将两个25位数字相加?

huangapple go评论72阅读模式
英文:

How can I add up two 25 digit numbers?

问题

我试图在C语言中进行约25位数的加法运算。我得到的结果与预期略有不同,可能是数据类型的原因。
英文:

I'm trying to work on addition of about 25 digit numbers in C. The result I am getting is a little different from the expected, possible cause datatype.

/* Online C Compiler and Editor */
#include <stdio.h>

int main()
{
    long double result;
    long double a;
    long double b;
    a = 51680708854858333333;
    b = 83621143489848333333,
    result = a + b;
    printf("Hello, World!\n");
    printf("can be written %.0Lf\n", result);

    return 0;
}

答案1

得分: 6

你可以以与小学教学相同的方式完成它:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* 用字符串表示的两个数字相加。结果以动态分配的内存返回,调用者需要负责释放。不会检查字符串是否只包含数字字符。

   结果可能包含前导零。可以在加法后进行测试,将所有字符左移一个位置,并根据需要重新分配。
*/
static char *add(const char *a, const char *b)
{
    // 测量字符串的长度。
    size_t la = strlen(a);
    size_t lb = strlen(b);

    // 为结果分配空间,以防有进位。
    size_t lc = (la < lb ? lb : la) + 1;

    // 为结果数字分配空间,还有一个终止空字符。
    char *c = malloc(lc + 1);
    if (!c)
    {
        fprintf(stderr, "错误,无法分配%zu字节的和。\n", lc + 1);
        exit(EXIT_FAILURE);
    }
    c[lc] = '\0';

    /* 从右向左添加数字。i计算数字的右边位置。
    */
    int carry = 0;
    for (size_t i = 0; i < lc; ++i)
    {
        /* 从每个加数中获取数字。只要i在一个数字内,就获取它的数字字符并减去'0',将其从数字字符('0'到'9')转换为普通数字(0到9)。当i在数字外部时,使用零。
        */
        int da = i < la ? a[la - 1 - i] - '0' : 0;
        int db = i < lb ? b[lb - 1 - i] - '0' : 0;

        /* 将数字相加,将和的低位记录在c中,并计算到下一列的进位。将c的数字从普通数字转换为数字字符。
        */
        int sum = da + db + carry;
        c[lc - 1 - i] = sum % 10 + '0';
        carry = sum / 10;
    }

    return c;
}

int main(void)
{
    const char a[] = "51680708854858333333";
    const char b[] = "83621143489848333333";

    char *c = add(a, b);

    printf("sum = %s.\n", c);

    free(c);
}
英文:

You can do it the same way taught in elementary school:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
/*	Add two numbers represented by strings of digit characters.  The result is
returned in dynamically allocated memory, which the caller is responsible
for freeing.  The strings are not tested to ensure they contain only
digits.
The result may contain a leading zero.  This could be eliminated by testing
after the addition, shifting all the characters left one space, and
reallocating if desired.
*/
static char *add(const char *a, const char *b)
{
//	Measure lengths of strings.
size_t la = strlen(a);
size_t lb = strlen(b);
//	Plan space for result, allowing an extra character in case of carry.
size_t lc = (la &lt; lb ? lb : la) + 1;
//	Allocate space for result digits plus a terminating null character.
char *c = malloc(lc+1);
if (!c)
{
fprintf(stderr, &quot;Error, unable to allocate %zu bytes for sum.\n&quot;, lc+1);
exit(EXIT_FAILURE);
}
c[lc] = &#39;\0&#39;;
/*	Add digits from right to left.  i counts positions from the right of
the numerals.
*/
int carry = 0;
for (size_t i = 0; i &lt; lc; ++i)
{
/*	Get digit from each addend.  While i is within a numeral, get its
digit character and subtract &#39;0&#39; to convert it from a digit
character (&#39;0&#39; to &#39;9&#39;) to a plain number (0 to 9).  When i is
outside the numeral, use zero.
*/
int da = i &lt; la ? a[la-1-i] - &#39;0&#39; : 0;
int db = i &lt; lb ? b[lb-1-i] - &#39;0&#39; : 0;
/*	Add the digits, record the low digit of the sum in c, and calculate
the carry to the next column.  The digit for c is converted from a
plain number to a digit character.
*/
int sum = da + db + carry;
c[lc-1-i] = sum % 10 + &#39;0&#39;;
carry = sum/10;
}
return c;
}
int main(void)
{
const char a[] = &quot;51680708854858333333&quot;;
const char b[] = &quot;83621143489848333333&quot;;
char *c = add(a, b);
printf(&quot;sum = %s.\n&quot;, c);
free(c);
}

答案2

得分: 3

以下是您要翻译的部分:

There is a subtle problem in your code: the literals 51680708854858333333 and 83621143489848333333 used to initialize the long double variables are actually parsed as integers and they both exceed the maximum value of the largest integer type long long int, which is 9223372036854775807.

You must add a trailing . to make them floating point constants and an L for long double constants. You will then get a result closer to the precise value, limited by the precision of the long double type:

#include <stdio.h>

int main(void)
{
    long double a = 51680708854858333333.L;
    long double b = 83621143489848333333.L;
    long double result = a + b;
    printf("%.0Lf + %.0Lf = %.0Lf\n", a, b, result);

    return 0;
}

The output on my macbook shows the limited precision of type long double with the default compiler chain for the M2 chip:

51680708854858334208 + 83621143489848328192 = 135301852344706662400

For better precision for 25 digit numbers, you can get away with 128-bit integers if your compiler supports them:

#include <stdio.h>

int main(void)
{
    long double a = 51680708854858333333.L;
    long double b = 83621143489848333333.L;
    long double result = a + b;
    printf("%.0Lf + %.0Lf = %.0Lf\n", a, b, result);

    __int128 e15 = 1000000000000000;
    __int128 aa = 51680 * e15 + 708854858333333;
    __int128 bb = 83621 * e15 + 143489848333333;
    __int128 cc = aa + bb;

    printf("%lld%015lld + %lld%015lld = %lld%015lld\n",
           (long long)(aa / e15), (long long)(aa % e15),
           (long long)(bb / e15), (long long)(bb % e15),
           (long long)(cc / e15), (long long)(cc % e15));

    return 0;
}

Output:

51680708854858334208 + 83621143489848328192 = 135301852344706662400
51680708854858333333 + 83621143489848333333 = 135301852344706666666

For a general solution, you can use a bignum package such as GMP, the GNU multiprecision library or implement the addition as a simplistic string-based operation:

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static char *add_strings(const char *s1, const char *s2) {
    // 省略部分代码
}

int main(int argc, char *argv[]) {
    // 省略部分代码
}
英文:

There is a subtile problem in your code: the literals 51680708854858333333 and 83621143489848333333 used to initialize the long double variables are actually parsed as integers and they both exceed the maximum value of the largest integer type long long int, which is 9223372036854775807.

You must add a trailing . to make them floating point constants and an L for long double constants. You will then get a result closer to the precise value, limited by the precision of the long double type:

#include &lt;stdio.h&gt;
int main(void)
{
long double a = 51680708854858333333.L;
long double b = 83621143489848333333.L;
long double result = a + b;
printf(&quot;%.0Lf + %.0Lf = %.0Lf\n&quot;, a, b, result);
return 0;
}

The output on my macbook shows the limited precision of type long double with the default compiler chain for the M2 chip:

51680708854858334208 + 83621143489848328192 = 135301852344706662400

For better precision for 25 digit numbers, you can get away with 128-bit integers if your compiler supports them:

#include &lt;stdio.h&gt;
int main(void)
{
long double a = 51680708854858333333.L;
long double b = 83621143489848333333.L;
long double result = a + b;
printf(&quot;%.0Lf + %.0Lf = %.0Lf\n&quot;, a, b, result);
__int128 e15 = 1000000000000000;
__int128 aa = 51680 * e15 + 708854858333333;
__int128 bb = 83621 * e15 + 143489848333333;
__int128 cc = aa + bb;
printf(&quot;%lld%015lld + %lld%015lld = %lld%015lld\n&quot;,
(long long)(aa / e15), (long long)(aa % e15),
(long long)(bb / e15), (long long)(bb % e15),
(long long)(cc / e15), (long long)(cc % e15));
return 0;
}

Output:

51680708854858334208 + 83621143489848328192 = 135301852344706662400
51680708854858333333 + 83621143489848333333 = 135301852344706666666

For a general solution, you can use a bignum package such as GMP, the GNU multiprecision library or implement the addition as a simplistic string based operation:

#include &lt;ctype.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
static char *add_strings(const char *s1, const char *s2) {
size_t len1, len2;
/* ignore leading spaces */
while (isspace((unsigned char)*s1))
s1++;
while (isspace((unsigned char)*s2))
s2++;
/* reject negative numbers. */
if (*s1 == &#39;-&#39; || *s2 == &#39;-&#39;) {
fprintf(stderr, &quot;negative numbers not supported\n&quot;);
exit(1);
}
/* ignore &#39;+&#39; sign */
if (*s1 == &#39;+&#39;)
s1++;
if (*s2 == &#39;+&#39;)
s2++;
/* reject invalid arguments (could just use 0) */
if (!isdigit((unsigned char)*s1) || !isdigit((unsigned char)*s2)) {
fprintf(stderr, &quot;invalid argument\n&quot;);
exit(1);
}
/* skip the leading zeroes */
while (*s1 == &#39;0&#39;)
s1++;
while (*s2 == &#39;0&#39;)
s2++;
/* count the digits */
for (len1 = 0; isdigit((unsigned char)s1[len1]); len1++)
continue;
for (len2 = 0; isdigit((unsigned char)s2[len2]); len2++)
continue;
/* result has at most one more digit than the longer argument */
size_t len3 = 1 + (len2 &gt; len1 ? len2 : len1);
char *s3 = malloc(len3 + 1);
if (s3 == NULL) {
fprintf(stderr, &quot;cannot allocate %zu bytes\n&quot;, len3 + 1);
exit(1);
}
/* compute the result starting from the least significant digits */
int carry = 0;
for (size_t i = len3; i --&gt; 0;) {
int digit1 = (len1 &gt; 0) ? s1[--len1] - &#39;0&#39; : 0;
int digit2 = (len2 &gt; 0) ? s2[--len2] - &#39;0&#39; : 0;
carry += digit1 + digit2;
s3[i] = &#39;0&#39; + carry % 10;
carry /= 10;
}
/* remove leading zero if any */
if (s3[0] == &#39;0&#39; &amp;&amp; len3 &gt; 1) {
memmove(s3, s3 + 1, --len3);
}
s3[len3] = &#39;\0&#39;;   /* set the null terminator */
return s3;
}
int main(int argc, char *argv[]) {
/* default values for testing */
const char *a = &quot;51680708854858333333&quot;;
const char *b = &quot;83621143489848333333&quot;;
if (argc &gt; 2) {
/* use command line arguments provided */
a = argv[1];
b = argv[2];
}
char *sum = add_strings(a, b);
printf(&quot;%s + %s = %s\n&quot;, a, b, sum);
free(sum);
return 0;
}

huangapple
  • 本文由 发表于 2023年6月27日 18:33:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76563973.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定