Unexpected Mathematical Division Output - C++ - c++

I have this segment of testing code (there is quite a lot of other material; however, it is extremely dense and likely irrelevant to this question), which has been producing some inexplicable output. When compiled, this block:
cout << team1[m].rating << endl;
cout << team2[n].rating << endl;
cout << team1.size() << endl;
cout << team2.size() << endl;
cout << (team2[n].rating - team1[m].rating) / team2.size() << endl;
cout << (team1[m].rating - team2[n].rating) / team1.size() << endl;
produces the output:
10
30
2
2
10
2147483638
'team1' and 'team2' are both of type vector<player> (without backslash) and the 'player' struct appears as follows:
struct player {
string name;
int rating;
player(string Name, int Rating) :
name(Name), rating(Rating) {}
};

team1.size() and team2.size() are unsigned (size_t) - change your code to:
cout << (team2[n].rating - team1[m].rating) / static_cast<int>(team2.size()) << endl;
cout << (team1[m].rating - team2[n].rating) / static_cast<int>(team1.size()) << endl;

(team1[m].rating - team2[n].rating) is equal to -20. This expression result is being promoted to unsigned int according to rules of mixed expressions and divided by team1.size(), yielding 2147483638 which is the unsigned int equivalent for signed int -10.

This occurs because the size() function of std::vector returns a size_t, which is unsigned. When dividing an int (such as the rating) by a size_t, the int is promoted to an unsigned int.
Converting a negative number to an unsigned value will cause that value to underflow, becoming larger than the maximum positive value which can be represented by the original signed type.
In order to prevent this, you need to explicitly state that the size() arguments should be converted to int before the division.
cout << (team2[n].rating - team1[m].rating) / static_cast<int>(team2.size()) << endl;
cout << (team1[m].rating - team2[n].rating) / static_cast<int>(team1.size()) << endl;

Related

Returning multiple values using pointers in a function

Can anyone help me to understand how to return multiple values using pointers in a function? I am confused with the following example.
Can we assign other values to int value besides 0 or 1, while the program can still run normally?
What does defining the value of 0 and 1 in the if statement and else statement do for us in the int factor function?
What does if(!error) statement do in the main ()?
#include <iostream>
using namespace std;
int factor(int n, int *p_addition, int *p_subtraction, int *p_squared, int *p_cubed)
{
int value = 0;
if (n >= 0 && n <= 100)
{
*p_addition = n + n;
*p_subtraction = n - n;
*p_squared = n*n;
*p_cubed = n*n*n;
value = 0;
}
else
{
value = 1;
}
// This function will return a value of 0 or 1
return value;
}
int main()
{
int number, num_add, num_sub, squared, cubed;
int error;
cout << "Enter a number between 0 and 100: ";
cin >> number;
error = factor(number, &num_add, &num_sub, &squared, &cubed);
if (!error)
{
cout << "number: " << number << endl;
cout << "num_add: " << num_add << endl;
cout << "num_sub: " << num_sub << endl;
cout << "squared: " << squared << endl;
cout << "cubed: " << cubed << endl;
}
else
{
cout << "Error encountered!!" << endl;
}
return 0;
}
int is at least 16 bits (depending on the system - hardware, operating system, 32-bit computing / vs. 64-bit computing), for numeric range, cf: https://en.cppreference.com/w/cpp/language/types (at least -32768 to 32767 for 16 bit integers).
factor contains return value, which (here) signifies to the caller, whether an error occurred. It has no other effect within factor.
The ! negates the boolean value, so that the test is for false. if with an int implicitly converts to bool and tests for error being 0: https://en.cppreference.com/w/cpp/language/implicit_conversion#Boolean_conversions The value zero (for integral [...]) [...] become[s] false. All other values become true.
So any value beside 0 would have the same effect instead as 1.
It would have been better to name value something like wrong_input_range.
It would have been better to make value a bool type instead of int and make the return type of factor bool, too.
Whether your main returns a value beside 0 in case of the error, you can decide by yourself. Within a script, the returned value of called programs often is tested to know, whether the script can continue.

double and float memory allocation on modern comptuers

I am learning about double and float and what the difference is. I ran a piece of code as posted below, to see how much memory is allocated depending on how many integers I add and decimal points but it seems that no matter how many integers I type I always get size 8 bytes for both float and double. I learned that float occupies 4 bytes, but Im starting to think that on modern computers that's not the case and perhaps this was the case back in the days and today we can use them interchangeably without affecting the results? Am I missing something here?
// C++ program to sizes of data types
#include<iostream>
using namespace std;
int main()
{
cout << "Size of int : " << sizeof(11111111111111111) << " bytes" << endl;
cout << "Size of float : " << sizeof(11111111111111111111111111111111111111111111111111111111111.1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111) << " bytes" <<endl;
cout << "Size of double : " << sizeof(.11111111111111111111111111111111111111111111111111111) << " bytes" << endl;
return 0;
}
You print the size of double on both lines, because both floating point literals has the type of double. If you want to create a float literal, append an f to it: 1.0f. This has the type of float. If you don't append an f to it, it will have the type of double.
Or you can just simply use sizeof(float).

Size of data types using pointers?

I want to see the size of data types on my computer. So I started with int datatype with this code :
#include <iostream>
using namespace std;
int main()
{
int t, *tpntr1, *tpntr2;
tpntr1 = &t;
cout << "The first address: \t" << tpntr1;
tpntr2 = ++tpntr1;
cout << "\n The second address : \t" << tpntr2;
unsigned int size= (tpntr2 - tpntr1);
cout << "\n the size of int : \t" << size<<"\n";
return 0;
}
After compiling in visual studio the size is returned to be 0. In a particular run the first address was 0028FBA4 and second was 0028FBA8 but the difference is coming out as zero. Can some one please point out what am I doing wrong here ? I guess its something related to hexadecimal to decimal conversion.
Here's a hint: Move the couts to the end to see what's going on:
#include <iostream>
using namespace std;
int main()
{
int t, *tpntr1, *tpntr2;
tpntr1 = &t;
tpntr2 = ++tpntr1;
unsigned int size= (tpntr2 - tpntr1);
cout << "The first address: \t" << tpntr1;
cout << "\n The second address : \t" << tpntr2;
cout << "\n the size of int : \t" << size<<"\n";
return 0;
}
The addresses are the same. You're literally assigning tpntr2 to tpntr1.
If you change tpntr2 = ++tpntr1 to
tpntr2 = tpntr1;
tpntr2++;
It will partially do what you want. Note that this will print 1 as the size. I may be mistaken, but pointer arithmetic takes into consideration the size of the type (someone please correct me if this isn't the case. I can't explain it otherwise).
As Carcigenicate pointed out, your main issue is that ++ modifies the value. However, you might also not get the result you want due to how pointer arithmetic works.
A corrected form of this would read:
tpntr1 = &t;
tpntr2 = tpntr1;
tpntr2++;
However, your result will be 1, because tpntr2 - tpntr1 will return the difference in terms of the number of ints. Since an int is 4 bytes (at least, in my implementation), this will print that the difference is 1, even though the memory addresses are 4 apart.
If you want the actual bytes (which would be 4), you need to cast to a type which will bypass this behavior. You have two options: cast the pointers to an int, which would make it a simple math operation on numbers, or reinterpret_cast<char*>, which will tell it to treat the pointers as being to one byte of memory. For example, this will show the size as 4:
int main()
{
int t, *tpntr1, *tpntr2;
tpntr1 = &t;
tpntr2 = tpntr1;
tpntr2++;
unsigned int size= (reinterpret_cast<char*>(tpntr2) - reinterpret_cast<char*>(tpntr1));
cout << "The first address: \t" << tpntr1;
cout << "\n The second address : \t" << tpntr2;
cout << "\n the size of int : \t" << size<<"\n";
return 0;
}

C++ safeguards exceeding limits of integer

I am working on a chapter review of a book: at the end of the chapter there are some questions/tasks which you are to complete.
I decided to do them in the format of a program rather than a text file:
#include <iostream>
int main(int argc, char* argv[]) {
std::cout << "Chapter review\n"
<< "1. Why does C++ have more than one integer type?\n"
<< "\tTo be able to represent more accurate values & save memory by only allocating what is needed for the task at hand.\n"
<< "2. Declare variables matching the following descriptions:\n"
<< "a.\tA short integer with the value 80:\n";
short myVal1 = 80;
std::cout << "\t\t\"short myVal1 = 80;\": " << myVal1 << std::endl
<< "b.\tAn unsigned int integer with the value 42,110:\n";
unsigned int myVal2 = 42110;
std::cout << "\t\t\"unsigned int myVal2 = 42110;\": " << myVal2 << std::endl
<< "c.\tAn integer with the value 3,000,000,000:\n";
float myVal3 = 3E+9;
std::cout << "\t\t\"float myVal3 = 3E+9;\": " << static_cast<unsigned int>(myVal3) << std::endl
<< "3. What safeguards does C++ provide to keep you from exceeding the limits of an integer type?\n"
<< "\tWhen it reaches maximum number it starts from the begging again (lowest point).\n"
<< "4. What is the distinction between 33L and 33?\n"
<< "\t33L is of type long, 33 is of type int.\n"
<< "5. Consider the two C++ statements that follow:\n\tchar grade = 65;\n\tchar grade = 'A';\nAre they equivalent?\n"
<< "\tYes, the ASCII decimal number for 'A' is '65'.\n"
<< "6. How could you use C++ to find out which character the code 88 represents?\nCome up with at least two ways.\n"
<< "\t1: \"static_cast<char>(88);\": " << static_cast<char>(88) << std::endl; // 1.
char myChar = 88;
std::cout << "\t2: \"char myChar = 88;\": " << myChar << std::endl // 2.
<< "\t3: \"std::cout << (char) 88;\" " << (char) 88 << std::endl // 3.
<< "\t4: \"std::cout << char (88);\": " << char (88) << std::endl // 4.
<< "7. Assigning a long value to a float can result in a rounding error. What about assigning long to double? long long to double?\n"
<< "\tlong -> double: Rounding error.\n\tlong long -> double: Significantly incorrect number and/or rounding error.\n"
<< "8. Evaluate the following expressions as C++ would:\n"
<< "a.\t8 * 9 + 2\n"
<< "\t\tMultiplication (8 * 9 = 72) -> addition (72 + 2 = 74).\n"
<< "b.\t6 * 3 / 4\n"
<< "\t\tMultiplication (6 * 3 = 18 -> division (18 / 4 = 4).\n"
<< "c.\t3 / 4 * 6\n"
<< "\t\tDivision (3 / 4 = 0) -> multiplication (0 * 6 = 0).\n"
<< "d.\t6.0 * 3 / 4\n"
<< "\t\tMultiplication (6.0 * 3 -> 18.0) -> division (18.0 / 4 = 4.5).\n"
<< "e.\t 15 % 4\n"
<< "\t\tDivision (15 / 4 = 3.75) Then returns the reminder, basically how many times can 4 go into 15 in this case that is 3 (3*4 = 12).\n"
<< "9. Suppose x1 and x2 are two type of double variables that you want to add as integers and assign to an integer variable. Construct a C++ statement for doing so. What if you wanted to add them as type double and then convert to int?\n"
<< "\t1: \"int myInt = static_cast<double>(doubleVar);\"\n\t2: \"int myInt = int (doubleVar);\".\n"
<< "10. What is the variable type for each of the following declarations?\n"
<< "a.\t\"auto cars = 15;\"\n\t\tint\n"
<< "b.\t\"auto iou = 150.37f;\"\n\t\tfloat\n"
<< "c.\t\"auto level = 'B';\"\n\t\tchar\n"
<< "d.\t\"auto crat = U'/U00002155';\"\n\t\twchar_t ?\n"
<< "e.\t\"auto fract = 8.25f/.25;\"\n\t\tfloat" << std::endl;
return 0;
}
It's been a while since I read chapter 3 due to moving/some other real life stuff.
What I am unsure about here is basically question number 3: it says safeguards as in plural.
However I am only aware of one: that it starts from the beginning again after reaching maximum value? Am I missing something here?
Let me know if you see any other errors also - I am doing this to learn after all :).
Basically I can't accept a comment as an answer so to sum it up:
There are none safeguards, I misunderstood that question which #n.m. clarified for me.
10.e was wrong as pointed out by #Jarod42, which is correct.
Thanks!
As for me "Declare variable of integer with the value 3,000,000,000" is:
unsigned anInteger = 3000000000;
cause c++ the 11th supplies 15 integer types and unsigned int is the smallest that can store such a big integer as 3 000 000 000.
C++ classifies integer overflow as "Undefined Behavior" - anything can happen as a result of it. This by itself may be called a "safeguard" (though it's a stretch), by the following thinking:
gcc has that -ftrapv compilation switch that makes your program crash when integer overflow happens. This allows you to debug your overflows easily. This feature is possible because C++ made it legal (by nature of Undefined Behavior) to make your program crash in these circumstances. I think the C++ Committee had this exact scenario in mind when making that part of the C++ Standard.
This is different from e.g. Java, where integer overflow causes wraparound, and is probably harder to debug.

Horrible number comes from nowhere

Out of nowhere I get quite a big result for this function... It should be very simple, but I can't see it now.
double prob_calculator_t::pimpl_t::B_full_term() const
{
double result = 0.0;
for (uint32_t j=0, j_end=U; j<j_end; j++)
{
uint32_t inhabited_columns = doc->row_sums[j];
// DEBUG
cout << "inhabited_columns: " << inhabited_columns << endl;
cout << "log_of_sum[j]: " << log_of_sum[j] << endl;
cout << "sum_of_log[j]: " << sum_of_log[j] << endl;
// end DEBUG
result += ( -inhabited_columns * log( log_of_sum[j] ) + sum_of_log[ j ] );
cout << "result: " << result << endl;
}
return result;
}
and where is the trace:
inhabited_columns: 1
log_of_sum[j]: 110.56
sum_of_log[j]: -2.81341
result: 2.02102e+10
inhabited_columns: 42
log_of_sum[j]: 110.56
sum_of_log[j]: -143.064
result: 4.04204e+10
Thanks for the help!
inhabited_columns is unsigned and I see a unary - just before it: -inhabited_columns.
(Note that unary - has a really high operator precedence; higher than * etc).
That is where your problem is! To quote Mike Seymour's answer:
When you negate it, the result is still unsigned; the value is reduced
modulo 232 to give a large positive value.
One fix would be to write
-(inhabited_columns * log(log_of_sum[j]))
as then the negation will be carried out in floating point
inhabited_columns is an unsigned type. When you negate it, the result is still unsigned; the value is reduced modulo 232 to give a large positive value.
You should change it to a sufficiently large signed type (maybe int32_t, if you're not going to have more than a couple of billion columns), or perhaps double since you're about to use it in double-precision arithmetic.