F
F
flash_back2016-02-16 12:45:07
C++ / C#
flash_back, 2016-02-16 12:45:07

An exercise from Stroustrup's book. A program about rice grains and a chessboard. How do you complete the task correctly?

Hello.
I did exercises for Bjarne Stroustrup's book "Programming. Principles and practice
of using C++".
The text of the exercises is:
ba953bd45bcc4d989cd3f707d19589c9.png
My solution for these exercises is:

#include <iostream>
#include <cmath>
#include <limits> 

using namespace std;

#define LOG_STEPS

void how_cells(double seeds)
{
  double sum = 0;
  int cell_numb=0;
  double seed_count=0;
  for ( cell_numb=1, seed_count=1.0; 
                    cell_numb <= 64;
            cell_numb++,seed_count*=2.0
    )
  {
    
    sum += seed_count;

    #ifdef LOG_STEPS
      cout << cell_numb << "  " << fixed << seed_count << "  " << fixed << sum <<  endl;
    #endif //LOG_STEPS

    if (sum>=seeds)
    {
      cout << "Answer is " << cell_numb << endl;
      break;
    }
  }
}

int main()
{
  //До какой клетки дойдем, чтобы получить хотя бы 1000 зерен риса в сумме
  cout << "Task#1. Cell numb if 1000 seeds:" << endl;
  how_cells(1000);
  //До какой клетки дойдем, чтобы получить хотя бы 1000000 зерен риса в сумме 
  cout << "Task#2. Cell numb if 1.000.000 seeds:" << endl;
  how_cells(1000000);
  //До какой клетки дойдем, чтобы получить хотя бы 1000000000 зерен риса в сумме
  cout << "Task#3. Cell numb if 1.000.000.000 seeds:" << endl;
  how_cells(1000000000);
  //До какой клетки дойдем, чтобы получить максимальное значение для int зерен риса в сумме
  cout << "Task#4. Cell numb in int max:" << endl;
  cout << "Max of int: " << numeric_limits<int>::max() << endl;
  how_cells(numeric_limits<int>::max());
  //До какой клетки дойдем, чтобы получить максимальное значение для double(только мантисса) зерен риса в сумме
  cout << "Task#5. Cell numb in double max:" << endl;
  //Должно быть такое значение 9223372036854775808.0 по замыслу Страуструпа, но младшие декады теряются
  cout << "Max of double (mantissa): " << 9223372036854775808.0 << endl; //берется только мантисса pow(2.0,63.0) != numeric_limits<double>::max()
  how_cells(9223372036854775808.0); //берется только мантисса pow(2.0,63.0) != numeric_limits<double>::max()
  system("pause");
  return 0;
}

When calculating the cell number in order to get a total of 1000, 1000000, 1000000, 217483647 (the maximum value for int), everything is fine. But for the maximum double value, not everything is unambiguous. The exercise does not explicitly say, but Stroustrup, as I understand it, only talks about the mantissa and the number of characters in it, the order does not seem to be taken into account (otherwise the maximum number with the loss of characters in the mantissa would be to the power of 308). Therefore, if we talk about the mantissa, I think that the number 9223372036854775808 was meant, i.e. the 63rd cell and the sum for it. But in fact we get 9223372036854775800 on this cell. sum after the 56th cell. But how then to determine this distortion in the program? You can, of course, set a constant in which there will be a value of 72057594037927936, it seems that it will not be overwritten when writing, but I think this solution is not completely true. Hence the question: what is the maximum value of the mantissa without loss of signs (lower decades) can be set for the double type and can it be found using standard library tools?
upd. I found library tools that provide the output of the number of available digits in the mantissa without distortion. Here is an example code:
#include <iostream>
#include <cfloat> //DBL_DIG
#include <limits> //std::numeric_limits<double>  


using namespace std;

int main()
{

  cout << "Number of digits (in decimal base) that can be represented without change." << endl;
  cout <<  "pure C. <cfloat>. Answer: " << DBL_DIG << endl;
  cout <<  "C++. <limits>.std::numeric_limits<double>. Answer: "<< numeric_limits<double>::digits10 << endl;
  
  //Нет искажения (15 цифр)
  cout << fixed << 999999999999999.0 << endl;
  //Есть искажение по последней цифре (16 цифр)
  cout << fixed << 9999999999999999.0 << endl;
  //Нет искажения (16 цифр)
  cout << fixed << 9999999999999912.0 << endl;
  //Нет искажения (17 цифр). Наш случай макисмального неискаженного числа. 
  //Т.е. вышли за 15 цифр.
  cout << fixed << 72057594037927936.0 << endl;


  system("pause");
  return 0;
}

It turns out that for the double typeit's guaranteed fifteen digits. It would be possible to get this value in the program and then count the number of digits of the sum when adding each subsequent cell. However, as you can see when executing the program, when 15 digits are exceeded, distortion is not always observed. And in our case with the board there is no distortion up to 17 digits (72057594037927936, the amount after the 56th cell). It turns out that it is not possible to determine the number of digits for the mantissa for which there will still be no distortion for each specific case (in particular, for ours) using the C / C ++ libraries. It is not clear whether it is possible to determine the cell and the amount corresponding to it (cell 56, sum 72057594037927936 ) in automatic mode and not just by comparing with the constant obtained by an earlier run of the program. At the moment I don't see such an option. Maybe someone knows how?
upd Wrote a solution to the problem with the unsigned long long type (8 bytes), it turns out to calculate the number of grains completely (2 ^ 64). The number of grains of the entire board fits into it. If there was one grain more, it would not fit. Decision:
#include <iostream>
#include <cmath>
#include <limits> 

using namespace std;


unsigned long long calc_sum()
{
  unsigned long long sum = 0;
  int cell_numb=0;
  unsigned long long seed_count=0;
  for ( cell_numb=1, seed_count=1; 
                    cell_numb <= 64;
            cell_numb++,seed_count*=2
    )
  {
    
    sum += seed_count;

    cout << cell_numb << "  " << seed_count << "  " << sum <<  endl;

  }

  return  sum;
}

int main()
{

  cout << "Max of unsigned long long: " << numeric_limits<unsigned long long>::max() << endl << endl;
  unsigned long long total_seed_count = calc_sum();
  cout << endl << "Total: " << total_seed_count << endl;
  system("pause");
  return 0;
}

But this does not solve the problem posed by Bjorn with the double type.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
R
res2001, 2016-02-16
@res2001

Why do you need a double? In the task it is said - a variable of type int. To be exact unsigned int with reference to this task.
In addition, calculating the degree in a cycle is not interesting.
The problem can be solved using bitwise arithmetic. Considering that each set bit in an unsigned int is 2 of somewhat equal bit position in the number. You need to find the position of the most significant bit in the number +1 - this will be the answer to the question of the problem.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question