所以我正在创建一个精确的十进制结构,将它的特征和尾数分别存储在long和unsigned long中因为我在做这件事,我不得不想出我自己的减法和加法函数。
在测试我的函数时,我遇到了麻烦的问题“负零”本质上,我不能表示-0.1到-0.9,因为如果不使用某种标志值,我就无法在零上加上负号这是背景信息,我会发布代码,这样你就可以看到我是如何做算术的但奇怪的是,我得到了一个高于ULONG_MAX的数字。具体来说,这是我日志的输出:
diff->right: 18446744073699551616
b->right10000000
MANTISSA_LIMIT: 100000000
ULONG_MAX: 18446744073709551615
Subtracting 10.10000000 from 10.00000000
Test: tests/bin/decimal.out(subtractDecimalsWithCarry+0x79) [0x40109f] Decimal: 0.10000000
以及代码:
帮助程序/十进制.h:
#ifndef __DECIMAL_H__
#include <limits.h>
#define MANTISSA_LIMIT 100000000
#define __DECIMAL_H__
typedef struct{ /* Calling them more convenient terms: */
long left; /* characteristic */
unsigned long right; /* mantissa */
}Decimal;
void createDecimal(long left, unsigned long right, Decimal * dec);
/* Perform arithmetic operations on Decimal structures */
void add_decimals(Decimal* a, Decimal* b, Decimal* sum);
void subtract_decimals(Decimal* a, Decimal* b, Decimal* diff);
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
void createDecimalFromString(Decimal * dec, const char * str);
#endif
然后是decimal.c的相关代码:
/* Subtract two decimals, a - b */
void subtract_decimals(Decimal* a, Decimal* b, Decimal* diff){
diff->left = a->left - b->left;
diff->right = a->right - b->right;
fprintf(stderr, "diff->right: %lu\n", diff->right);
fprintf(stderr, "b->right%lu\n", b->right);
fprintf(stderr, "MANTISSA_LIMIT: %d\n", MANTISSA_LIMIT);
fprintf(stderr, "ULONG_MAX: %lu\n", ULONG_MAX);
if(diff->right > MANTISSA_LIMIT) {
if(diff->right != 18446744073699551616UL)
diff->left -= 1;
else
diff->left *= -1; /* This is where I might put a flag for -0*/
diff->right = ULONG_MAX - diff->right + (18446744073699551616UL == diff->right ? 1 : 0); /* +1 because of the wrap around, we have to 'count' 0. */
}
}
void createDecimalFromString(Decimal * dec, const char * str){
long left;
unsigned long right;
char * dotLocation;
char rawLeft[9];
char rawRight[9];
int i;
int dotPos;
long leadingZeros;
int numDetected;
if(str == NULL)
return;
bzero(rawLeft,9);
bzero(rawRight,9);
dotLocation = strstr(str, ".");
leadingZeros = numDetected = 0;
if(dotLocation == NULL){
left = atol(str);
right = 0;
}else{
/* ghetto strncpy */
for(i=0; i != 9 && str[i] != *dotLocation; ++i)
rawLeft[i] = str[i];
rawLeft[i] = '\0';
dotPos = i+1;
left = atol(rawLeft);
for(i=0; i != 9 && str[dotPos] != '\0'; ++i,++dotPos){
if(str[dotPos] == '0' && numDetected == 0)
leadingZeros++;
else
numDetected = 1;
rawRight[i] = str[dotPos];
}
rawRight[i] = '\0';
right = strtoul(rawRight,NULL,10);
if(leadingZeros > 0)
/* subtract the leading zeros, then also the powers of ten taken by the number itself*/
right = (right*(powlu(10,7-leadingZeros-(i-2))));
else
right = right*(powlu(10,(i > 1 ? 8-(i-1) : 7 )));
}
dec->left = left;
dec->right = right;
}
最后是调用代码:
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <unistd.h>
#include "helpers/decimal.h"
void traceAndPrintDecimal(Decimal testDec){
int nptrs;
void *buffer[100];
char **strings;
nptrs = backtrace(buffer, 100);
strings = backtrace_symbols(buffer, nptrs);
printf("Test: %s Decimal: %ld.%08lu\n", strings[1], testDec.left, testDec.right);
free(strings);
}
void subtractDecimalsWithCarry(){
Decimal oper1;
Decimal oper2;
Decimal result;
createDecimalFromString(&oper1, "10.0");
createDecimalFromString(&oper2, "10.1");
subtract_decimals(&oper1, &oper2, &result);
printf("Subtracting %ld.%08lu from %ld.%08lu\n",oper2.left,oper2.right,oper1.left,oper1.right);
traceAndPrintDecimal(result);
}
int main(){
subtractDecimalsWithCarry();
return 0;
}
以及我要编译的makefile文件:
decimal.o: src/helpers/decimal.c
cc -I./headers -std=gnu99 -pedantic -Wall -Wextra -Werror -g -c src/helpers/decimal.c -o obj/decimal.o
test-decimal: tests/decimal-test.c decimal.o
cc -I./headers -std=gnu99 -pedantic -Wall -Wextra -Werror -g tests/decimal-test.c obj/decimal.o -o tests/bin/decimal.out -lm -rdynamic
奇怪的是,
diff->right
比ULONG_MAX大,有人知道这是为什么吗如果你需要更多的信息,请告诉我,我会尽力更新问题。 最佳答案
错误的“超过ULONG_MAX的数字”。
乍一看,值为“18446744073699551616”的diff->right
似乎大于ULONG_MAX(“18446744073709551615”)但是少了99999999(@不洁)
OP在评论中说“知道为什么那个地方会有点歪吗由于尾数的工作方式,该数字只应减少1000000但现在是10000001英镑暗示这是不正确的。
// from createDecimalFromString(&oper1, "10.0");
oper1.right = 0
// from createDecimalFromString(&oper2, "10.1");
oper1.right = 10000000
// from subtract_decimals(&oper1, &oper2, &result)
diff->right = oper1.right - oper2.right --> 18446744073699551616
unsigned
减法在C中有很好的定义。在这种情况下,差值oper1.right - oper2.right
将在数学上导致oper1.right - oper1.right + (ULONG_MAX + 1)
。" ... 不能由结果的无符号整数类型表示的结果将被减少为比结果类型所能表示的最大值大一个数的模。“C11 6.2.5 8
关于c - 无符号算术期间大于ULONG_MAX的数字,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19095288/