简体   繁体   English

c中的变量如何存储数学运算?

[英]How mathematical operations are stored in variables in c?

I've been using Computer Systems: A Programmer's Perspective to know more about computer architecture.我一直在使用 Computer Systems: A Programmer's Perspective 来了解有关计算机体系结构的更多信息。 Today, I was studying unsigned and signed addition and the handling of overflows in both cases.今天,我正在研究无符号和有符号的加法以及这两种情况下的溢出处理。

I didn't have a problem with unsigned addition, so signed addition wasn't a problem because it was basically unsigned addition with conversions from signed to unsigned and unsigned to signed, also stated in the book as:我对无符号加法没有问题,所以有符号加法不是问题,因为它基本上是无符号加法,从有符号到无符号和无符号到有符号的转换,在书中也有说明:

The w-bit two's-complement sum of two numbers has the exact same bit-level representation as the unsigned sum.两个数字的 w 位二进制补码和具有与无符号和完全相同的位级表示。 In fact, most computers use the same machine instruction to perform either unsigned or signed addition.事实上,大多数计算机使用相同的机器指令来执行无符号或有符号加法。

Also with the formula, where w represents the word size:同样用公式,其中 w 代表字长:


Coming from this I get to the exercises and there was this exercise with a buggy code that I need to analyze从这里我开始练习,这个练习有一个错误的代码,我需要分析

int tadd_ok(int x, int y) {
    int sum = x+y;
    return (sum-x == y) && (sum-y == x);
}

In the answer, it says the operation sum-x in the sum-x == y causes an abelian group to form so it turns into an x+yx and y will be left no matter the sum value is, therefore, resulting to an incorrect evaluation.在答案中,它说sum-x == y中的操作sum-x导致形成一个阿贝尔群,因此它变成x+yx并且无论总和值如何,y 都会留下,因此,导致不正确的评价。

So, here's the thing I wonder: I always thought, intuitively, that the value will be assigned after an operation to the variable, not the operation itself because if this weren't the case, the variable sum would just have the value of x+y , not the operation.所以,这就是我想知道的事情:我一直直觉地认为,值将在对变量进行操作之后分配,而不是操作本身,因为如果不是这种情况,变量sum将只有x+y的值x+y ,不是操作。 Then it would result in something like some_value-x in the latter operation not causing an abelian group to form, so it would behave as expected.然后它会在后一个操作中导致类似于some_value-x的东西不会导致形成阿贝尔群,因此它会按预期运行。 Instead, it carried the operation itself to the sum-x == y相反,它将操作本身带到了sum-x == y

Is this happening just because the value x+y cannot be stored in an int because of the size, so it just carries the operation, or does it always work like this, even when there's no potential overflow?发生这种情况是因为x+y值由于大小而不能存储在 int 中,所以它只是进行操作,还是它总是这样工作,即使没有潜在的溢出? If so, is it always the case for every other programming language?如果是这样,其他所有编程语言是否总是如此?

For this:为了这:

int tadd_ok(int x, int y) {
    int sum = x+y;
    return (sum-x == y) && (sum-y == x);
}

What you'd expect is that for some values of x and y the addition will cause an overflow.您所期望的是,对于xy的某些值,相加会导致溢出。 For signed numbers, C does not assume anything about how signed numbers are represented (eg an implementation might use "twos complement" and might not) and signed integer overflows are undefined behavior (might wrap around, might format your hard drive).对于有符号数,C 不假设有符号数的表示方式(例如,实现可能使用“二进制补码”,也可能不会),并且有符号的 integer 溢出是未定义的行为(可能会环绕,可能会格式化您的硬盘驱动器)。 Because overflow is undefined behavior the compiler can do anything it likes, including assuming that it never happens (which is something that some compilers are known to do).因为溢出是未定义的行为,编译器可以做任何它喜欢的事情,包括假设它永远不会发生(这是一些编译器已知的事情)。

If the compiler does assume that the undefined behavior never happens (that x+y never overflows), then the compiler can also assume that (sum-x == y) && (sum-y == x) is always true, and the compiler can optimize the code into:如果编译器确实假设未定义的行为永远不会发生( x+y永远不会溢出),那么编译器也可以假设(sum-x == y) && (sum-y == x)始终为真,并且编译器可以将代码优化成:

int tadd_ok(int x, int y) {
    return true;
}

In the answer, it says the operation sum-x in the sum-x == y causes an abelian group to form so it turns into an x+yx and y will be left no matter the sum value is, therefore, resulting to an incorrect evaluation.在答案中,它说 sum-x == y 中的操作 sum-x 导致形成一个阿贝尔群,因此它变成 x+yx 并且无论总和值如何,y 都会留下,因此,导致不正确的评价。

That is "potentially possible in practice" (if the implementation uses "twos compliment" representation for signed integers, and if "undefined behavior" becomes wrapping/truncation) but it's not guaranteed, even if the underlying CPU uses "twos compliment" and wrapping/truncation.那是“在实践中可能实现的”(如果实现对有符号整数使用“双恭维”表示,并且如果“未定义的行为”变为包装/截断)但不能保证,即使底层 CPU 使用“双恭维”和包装/截断。

So, here's the thing I wonder: I always thought, intuitively, that the value will be assigned after an operation to the variable, not the operation itself because if this weren't the case, the variable sum would just have the value of x+y, not the operation.所以,这就是我想知道的事情:我一直直觉地认为,值将在对变量进行操作之后分配,而不是操作本身,因为如果不是这种情况,变量 sum 将只有 x 的值+y,不是操作。 Then it would result in something like some_value-x in the latter operation not causing an abelian group to form, so it would behave as expected.然后它会在后一个操作中导致类似于 some_value-x 的东西不会导致形成阿贝尔群,因此它会按预期运行。 Instead, it carried the operation itself to the sum-x == y相反,它将操作本身带到了 sum-x == y

For "potentially possible in practice (but not guaranteed)";对于“在实践中可能(但不保证)”; the value is assigned.该值已分配。 For example, with 16-bit int , with something like tadd_ok(30000, 30000) the sum = x + y;例如,对于 16 位int ,使用tadd_ok(30000, 30000)之类的sum = x + y; would do sum = 30000 + 30000 = +60000 = too big to fit = -5536 due to wrapping and then sum - x = -5536 - 30000 = -35536 = too big to fit = +30000 due to wrapping = y .会做sum = 30000 + 30000 = +60000 = too big to fit = -5536 due to wrapping ,然后sum - x = -5536 - 30000 = -35536 = too big to fit = +30000 due to wrapping = y

Is this happening just because the value x+y cannot be stored in an int because of the size, so it just carries the operation, or does it always work like this, even when there's no potential overflow?发生这种情况是因为 x+y 值由于大小而不能存储在 int 中,所以它只是进行操作,还是它总是这样工作,即使没有潜在的溢出?

If it happens like this;如果发生这样的事情; then it happens because the first overflow (in sum = x + y; ) causes wrapping, followed by a second overflow (in sum - x ) and a third overflow (in sum - y ) which cause more wrapping that cancels out the wrapping caused by the first overflow.然后它发生是因为第一次溢出(在sum = x + y;中)导致换行,然后是第二次溢出(在sum - x中)和第三次溢出(在sum - y中)导致更多的换行,从而抵消了造成的换行通过第一次溢出。

If so, is it always the case for every other programming language?如果是这样,其他所有编程语言是否总是如此?

It's not always the case for C. C 并非总是如此。 For example, with 16-bit int using "sign and magnitude" representation for signed integers, with something like tadd_ok(30000, 30000) the sum = x + y;例如,对于有符号整数,使用“符号和大小”表示的 16 位int ,例如tadd_ok(30000, 30000) sum = x + y; could do sum = 30000 + 30000 = +60000 = too big to fit = +27232 due to wrapping of the magnitude part only and then sum - x = 27232 - 30000 = -2768 != y .可以做sum = 30000 + 30000 = +60000 = too big to fit = +27232 due to wrapping of the magnitude part only然后sum - x = 27232 - 30000 = -2768 != y Of course in this case (because it's undefined behaviour) the compiler could still always return true (as described at the start);当然在这种情况下(因为它是未定义的行为)编译器仍然可以始终返回 true (如开头所述); and the same code might behave one way (with optimizer disabled) and another way (with optimizer enabled).并且相同的代码可能以一种方式(禁用优化器)和另一种方式(启用优化器)运行。

In general;一般来说; "twos complement" is much more common and (for performance reasons) most languages don't do anything for overflows; “二进制补码”更为常见,并且(出于性能原因)大多数语言不会对溢出做任何事情; so (without optimization) the "potentially possible in practice (but not guaranteed)" behavior isn't uncommon in other languages.所以(没有优化)“在实践中可能(但不能保证)”的行为在其他语言中并不少见。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM