I have a very simple algorithm written in C, which takes values from array of int16_t
, multiplies those values by their positions and stores into array of int32_t
. There is another variable sum
of type int64_t
storing sum of all values in the resulting _slops
array. Here is the code.
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
// these variables initialized separately
int16_t *from;
int32_t *_slops;
int32_t _overlapSize;
...
// main algorithm
int32_t pos;
int64_t sum = 0;
for(pos = 0; pos < _overlapSize; pos++) {
_slops[pos] = (from[pos] * pos * (_overlapSize - pos));
sum += (int64_t) _slops[pos];
if (pos == 2) {
LOGD("1 ---: %d", (from[pos] * pos * (_overlapSize - pos)));
LOGD("2 ---: %d", _slops[pos]);
LOGD("3 sum: %d", sum);
}
}
LOGD("sum: %d", sum);
When I run the code, I see that resulting array of _slops
has correct values in it, but the sum
variable has same value all the time.
02-26 15:58:10.762: D/player(17466): 1 ---: 1154560
02-26 15:58:10.762: D/player(17466): 2 ---: 1154560
02-26 15:58:10.762: D/player(17466): 3 sum: 1504780888
02-26 15:58:10.762: D/player(17466): sum: 1504780904
02-26 15:58:10.840: D/player(17466): 1 ---: 890560
02-26 15:58:10.840: D/player(17466): 2 ---: 890560
02-26 15:58:10.848: D/player(17466): 3 sum: 1504780888
02-26 15:58:10.848: D/player(17466): sum: 1504780904
02-26 15:58:10.848: D/player(17466): 1 ---: 1791680
02-26 15:58:10.848: D/player(17466): 2 ---: 1791680
02-26 15:58:10.848: D/player(17466): 3 sum: 1504780888
02-26 15:58:10.848: D/player(17466): sum: 1504780904
I tried to change type of sum
to float
, but the result stayed the same. I am quite sure I do something wrong with type casting ( int32_t
to int64_t
or int32_t
to float
), but I wasn't able to find the right way for doing it.
What is the right way for doing this in C? And in general, if I multiply two int16_t
values, and what to have a larger result (let's say int32_t
), how do I do this? Any help is highly appreciated.
Unless int64_t
is an alias for int
on your machine, you are using the wrong printf
format directive. Try this instead:
LOGD("sum: %" PRId64, sum);
PRId64
is a macro defined in <inttypes.h>
.
If you are using GCC, compiling with -Wformat
would have generated an error about a format mismatch. -Wall
will include -Wformat
, along with many other useful warnings.
To your second question (about how to widen a result of a binary arithmetic operation that uses narrow type arguments), this is done by making at least one of the operands the width you desire. This can be done with a cast:
int16_t a = A_VAL;
int16_t b = B_VAL;
int32_t c = a + (int32_t)b;
As indicated by maverik 's answer , you have a possibility for signed integer overflow in the expression that is assigned to _slops[pos]
. If _overlapSize
is greater than 2 9 , then the largest product of pos * (_overlapSize - pos)
is greater than 2 16 , meaning its product against from[pos]
could have a result greater than 2 31 .
Here is the problem:
_slops[pos] = (from[pos] * pos * (_overlapSize - pos));
The _slops[pos]
is a type of int32_t
. The expression (from[pos] * pos * (_overlapSize - pos))
in some cases cannot be stored in int32_t
because from[pos]
is int16_t
is multiplied by pos
which is int32_t
and the result can be bigger than int32_t
(consider maximum value for int16_t
that is 2^15
and maximum value for int32_t
that is 2^31
. 2^15
* 2^31
= 2^46
which can't be stored as int32_t
without truncating.
But you write it back to _slops[pos]
which is int32_t
. In this line:
sum += (int64_t) _slops[pos];
cast is useless and doesn't prevent narrowing. I suggest change _slops
type to int64_t *
or to use temporary variable to calculate the result:
int64_t tmp = ((int64_t) from[pos] * pos * (_overlapSize - pos));
I don't know how big can the pos
be but the overall expression is not safe in this sense.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.