Exercise 3-28 (Print, set bytes in double arrays)

Chapter_3     Exercise_3-27 Exercise_3-29







Exercise 3-28     TCP1, p. 230


Exercise 3-28. Create a function that takes a pointer to an array of double and a value indicating the size of that array. The function should print each element in the array. Now create an array of double and initialize each element to zero, then use your function to print the array. Next use reinterpret_cast to cast the starting address of your array to an unsigned char*, and set each byte of the array to 1 (hint: you’ll need to use sizeof to calculate the number of bytes in a double). Now use your array-printing function to print the results. Why do you think each element was not set to the value 1.0?




CONTENTS:     double.c     Double.cpp




double.c         download


#include <stdio.h> // for printf(), putchar()

#define FLOAT 0 // used
#define DOUBLE 1 // for
#define LONGDOUBLE 2 // printing
#define SIZE 5 // array size
// we assume sizeof(char) = 1 byte
void set(char* array, int bytes, int value); // initialize or set array
void print(void* array, int size, int type); // print array
// type: 0 for float, 1 for double, 2 for long double
void printBinary(const unsigned char val); // Display a byte in binary
void printData(unsigned char*, int); // Display a data type in binary
void printData2(unsigned char*, int); // Display data type in binary (2 parts)

int main()
{
float fArray[SIZE];
// automatically convert float* (fArray) to void* in function call:
print(fArray, SIZE, FLOAT); // print uninitialized array
printData((unsigned char*)(fArray), sizeof(float)); // &fArray[0]
char* cp = (char*)fArray; // &fArray[0]
/*
// Alternative conversion:
void* p = (void*)fArray; // &fArray[0]
char* cp = (char*)p;
*/
set(cp, SIZE*sizeof(float), 0); // initialize array to 0
print(fArray, SIZE, FLOAT); // print initialized array
printData((unsigned char*)(fArray), sizeof(float));
set(cp, SIZE*sizeof(float), 1); // set each byte to 00000001
print(fArray, SIZE, FLOAT); // print initialized array
printData((unsigned char*)(fArray), sizeof(float));
set(cp, SIZE*sizeof(float), 0xff); // set array to 1...1
print(fArray, SIZE, FLOAT); // print array
printData((unsigned char*)(fArray), sizeof(float));
putchar('\n');

double dArray[SIZE];
// automatically convert double* (dArray) to void* in function call:
print(dArray, SIZE, DOUBLE); // print uninitialized array
printData((unsigned char*)(dArray), sizeof(double)); // &dArray[0]
cp = (char*)dArray; // &dArray[0]
set(cp, SIZE*sizeof(double), 0); // initialize array to 0
print(dArray, SIZE, DOUBLE); // print initialized array
printData((unsigned char*)(dArray), sizeof(double));
set(cp, SIZE*sizeof(double), 1); // set each byte to 00000001
print(dArray, SIZE, DOUBLE); // print initialized array
printData((unsigned char*)(dArray), sizeof(double));
set(cp, SIZE*sizeof(double), 0xff); // set array to 1...1
print(dArray, SIZE, DOUBLE); // print array
printData((unsigned char*)(dArray), sizeof(double));
putchar('\n');

long double ldArray[SIZE];
// automatically convert long double* (ldArray) to void* in function call:
print(ldArray, SIZE, LONGDOUBLE); // print uninitialized array
printData2((unsigned char*)(ldArray), sizeof(long double)); // &ldArray[0]
printData2((unsigned char*)(ldArray+1), sizeof(long double));
printData2((unsigned char*)(&ldArray[2]), sizeof(long double));
cp = (char*)ldArray; // &ldArray[0]
set(cp, SIZE*sizeof(long double), 0); // initialize array to 0
print(ldArray, SIZE, LONGDOUBLE); // print initialized array
printData2((unsigned char*)(ldArray), sizeof(long double));
set(cp, SIZE*sizeof(long double), 1); // set each byte to 00000001
print(ldArray, SIZE, LONGDOUBLE); // print initialized array
printData2((unsigned char*)(ldArray), sizeof(long double));
set(cp, SIZE*sizeof(long double), 0xff); // set array to 1...1
print(ldArray, SIZE, LONGDOUBLE); // print array
printData2((unsigned char*)(ldArray), sizeof(long double));

return 0;
}

void set(char* array, int bytes, int value) // initialize or set array
{ // set each byte of the contiguous array to `value'
for (int i = 0; i < bytes; i++)
{array[i] = value;}
}
void print(void* array, int size, int type) // print array
{ // type: 0 for float, 1 for double, 2 for long double
int i;
float* fArray;
double* dArray;
long double* ldArray;

switch(type)
{
case FLOAT: // 0
fArray = (float*)array;
for (i = 0; i < size; i++)
{printf("%g, ", fArray[i]);}
break;
case DOUBLE: // 1
dArray = (double*)array;
for (i = 0; i < size; i++)
{printf("%g, ", dArray[i]);}
break;
case LONGDOUBLE: // 2
ldArray = (long double*)array;
for (i = 0; i < size; i++)
{printf("%Lg, ", ldArray[i]);}
break;
default:
printf("Not implemented");
break;
}
putchar('\n');
}

void printBinary(const unsigned char val) // Display a byte in binary
{
int i;

for(i = 7; i >= 0; i--)
{ // print bits from first (most significant) to last (least significant)
if(val & (1 << i)) // set (1) bit
{putchar('1');}
else {putchar('0');} // 0 bit
}
}

void printData(unsigned char* cp, int size) // Display a data type in binary
{ // sizeof(float) = 4: cp[3], cp[2], cp[1], cp[0]
for(; size > 0; size--)
{printBinary(cp[size-1]);}
putchar('\n');
}
// Display a data type in binary (2 parts):
void printData2(unsigned char* cp, int size) // for long double
{ // sizeof(long double) = 16, 2 parts of 8 bytes
int half = size / 2; // we assume size is even
for(; size > half; size--) // second half:
{printBinary(cp[size-1]);} // cp[15], ..., cp[8]
putchar('\n');
for(; size > 0; size--) // first half:
{printBinary(cp[size-1]);} // cp[7], ..., cp[0]
putchar('\n');
}
/*
gcc double.c -o double
./double
0, 0, 0, 0, 0, // garbage
00000000000000000000000000000000
0, 0, 0, 0, 0,
00000000000000000000000000000000
2.36943e-38, 2.36943e-38, 2.36943e-38, 2.36943e-38, 2.36943e-38,
00000001000000010000000100000001
-nan, -nan, -nan, -nan, -nan, // exp bits all 1, mantissa not 0
11111111111111111111111111111111 // sign bit is 1, negative

0, 0, 0, 0, 0, // garbage
0000000000000000000000000000000000000000000000000000000000000000
0, 0, 0, 0, 0,
0000000000000000000000000000000000000000000000000000000000000000
7.7486e-304, 7.7486e-304, 7.7486e-304, 7.7486e-304, 7.7486e-304,
0000000100000001000000010000000100000001000000010000000100000001
-nan, -nan, -nan, -nan, -nan, // sign bit 1, exp bits 1, mantissa not 0
1111111111111111111111111111111111111111111111111111111111111111

-nan, nan, -nan, -nan, -nan, // garbage (Unnormal, invalid operands)
0000000000000000000000000000000000000000111100001011011011111111 // part 2
0000000000000000010101011011111100010010011000110111000001000000 // part 1
0000000000000000011111111111111100001010100101010101011101110111 // last bits
0000000000000000000000000000000000000000000000000000000011000010 // first
0000000000000000010101011011111100010010011000111000100000001101 // 127-64
0000000000000000011111111111111100001010100101010101011101110110 // 63-0
0, 0, 0, 0, 0, (sign bit 79 is 0, positive)
0000000000000000000000000000000000000000000000000000000000000000 // 78-64 (0)
0000000000000000000000000000000000000000000000000000000000000000 // 63-0 (0)
nan, nan, nan, nan, nan, // Unnormal, invalid operands (bit 79 is 0, positive)
0000000100000001000000010000000100000001000000010000000100000001 // 78-64 (0/1)
0000000100000001000000010000000100000001000000010000000100000001 // 63 (0)
-nan, -nan, -nan, -nan, -nan, // Quiet Not a Number (bit 79 is 1, negative)
1111111111111111111111111111111111111111111111111111111111111111 // 78-64 (1)
1111111111111111111111111111111111111111111111111111111111111111 // 63-0 (1)
*/





Notes:  See Single-precision, Double-precision, and Extended_precision (for long_double) floating-point formats, as well as NaN (not a number) on Wikipedia. See also Exercise_3-26.

00000001000000010000000100000001 = ((-1)^0)*2^(2^1-127)*(1+2^(-7)+2^(-15)+2^(-23)) = 1*2^(-125)*1.00784313679 ~ 2.36943e-38
(here ^ means "raised to power" and ~ means "approximates to").
etc.











Double.cpp         download


#include <iostream>
using std::cout;
using std::endl;

#define SIZE 5 // array size
// we assume sizeof(char) = 1 byte
void set(char* array, int bytes, int value); // initialize array
template <typename T> // generics
void print(T* array, int size); // print array
void printBinary(const unsigned char val); // Display a byte in binary
void printData(unsigned char*, int); // Display a data type in binary
void printData2(unsigned char*, int); // Display data type in binary (2 parts)

int main()
{
float fArray[SIZE];
// automatically convert float* (fArray) to void* in function call:
print<float>(fArray, SIZE); // print uninitialized array
printData(reinterpret_cast<unsigned char*>(fArray), sizeof(float));
printData(reinterpret_cast<unsigned char*>(fArray+1), sizeof(float));
printData(reinterpret_cast<unsigned char*>(&fArray[2]), sizeof(float));
char* cp = reinterpret_cast<char*>(fArray); // &fArray[0]
/*
// Alternative conversion:
void* p = static_cast<void*>fArray; // &fArray[0]
char* cp = static_cast<char*>p;
*/
set(cp, SIZE*sizeof(float), 0); // initialize array to 0
print<float>(fArray, SIZE); // print initialized array
printData(reinterpret_cast<unsigned char*>(fArray), sizeof(float));
set(cp, SIZE*sizeof(float), 1); // set each byte to 00000001
print<float>(fArray, SIZE); // print initialized array
printData(reinterpret_cast<unsigned char*>(fArray), sizeof(float));
set(cp, SIZE*sizeof(float), 0xff); // set array to 1...1
print<float>(fArray, SIZE); // print array
printData(reinterpret_cast<unsigned char*>(fArray), sizeof(float));
cout << endl;

double dArray[SIZE];
// automatically convert double* (dArray) to void* in function call:
print<double>(dArray, SIZE); // print uninitialized array
printData(reinterpret_cast<unsigned char*>(dArray), sizeof(double));
printData(reinterpret_cast<unsigned char*>(dArray+1), sizeof(double));
printData(reinterpret_cast<unsigned char*>(&dArray[2]), sizeof(double));
cp = reinterpret_cast<char*>(dArray); // &dArray[0]
set(cp, SIZE*sizeof(double), 0); // initialize array to 0
print<double>(dArray, SIZE); // print initialized array
printData(reinterpret_cast<unsigned char*>(dArray), sizeof(double));
set(cp, SIZE*sizeof(double), 1); // set each byte to 00000001
print<double>(dArray, SIZE); // print initialized array
printData(reinterpret_cast<unsigned char*>(dArray), sizeof(double));
set(cp, SIZE*sizeof(double), 0xff); // set array to 1...1
print<double>(dArray, SIZE); // print array
printData(reinterpret_cast<unsigned char*>(dArray), sizeof(double));
cout << endl;

long double ldArray[SIZE];
// automatically convert long double* (ldArray) to void* in function call:
print<long double>(ldArray, SIZE); // print uninitialized array
printData2(reinterpret_cast<unsigned char*>(ldArray), sizeof(long double));
printData2(reinterpret_cast<unsigned char*>(ldArray+1), sizeof(long double));
printData2(reinterpret_cast<unsigned char*>(&ldArray[2]), sizeof(long double));
cp = reinterpret_cast<char*>(ldArray); // &dArray[0]
set(cp, SIZE*sizeof(long double), 0); // initialize array to 0
print<long double>(ldArray, SIZE); // print initialized array
printData2(reinterpret_cast<unsigned char*>(ldArray), sizeof(long double));
set(cp, SIZE*sizeof(long double), 1); // set each byte to 00000001
print<long double>(ldArray, SIZE); // print initialized array
printData2(reinterpret_cast<unsigned char*>(ldArray), sizeof(long double));
set(cp, SIZE*sizeof(long double), 0xff); // set array to 1...1
print<long double>(ldArray, SIZE); // print array
printData2(reinterpret_cast<unsigned char*>(ldArray), sizeof(long double));

return 0;
}

void set(char* array, int bytes, int value) // initialize array
{ // set each byte of the contiguous array to `value'
for (int i = 0; i < bytes; i++)
{array[i] = value;}
}
template <typename T>
void print(T* array, int size) // print array
{
for (int i = 0; i < size; i++)
{cout << array[i] << ", ";}
cout << endl;
}

void printBinary(const unsigned char val) // Display a byte in binary
{
for(int i = 7; i >= 0; i--)
{ // print bits from first (most significant) to last (least significant)
if(val & (1 << i)) // set (1) bit
{cout << "1";}
else {cout << "0";} // 0 bit
}
}

void printData(unsigned char* cp, int size) // Display a data type in binary
{ // sizeof(float) = 4: cp[3], cp[2], cp[1], cp[0]
for(; size > 0; size--)
{printBinary(cp[size-1]);}
cout << endl;
}
// Display a data type in binary (2 parts):
void printData2(unsigned char* cp, int size) // for long double
{ // sizeof(long double) = 16, 2 parts of 8 bytes
int half = size / 2; // we assume size is even
for(; size > half; size--) // second half:
{printBinary(cp[size-1]);} // cp[15], ..., cp[8]
cout << endl;
for(; size > 0; size--) // first half:
{printBinary(cp[size-1]);} // cp[7], ..., cp[0]
cout << endl;
}
/*
g++ Double.cpp -o Double
./Double
-2.68742e+32, 4.57552e-41, -2.45652e+32, 4.57552e-41, -2.30727e+32, // garbage
11110101010101000000000000000000
00000000000000000111111110001100
11110101010000011100100100000000
0, 0, 0, 0, 0,
00000000000000000000000000000000
2.36943e-38, 2.36943e-38, 2.36943e-38, 2.36943e-38, 2.36943e-38,
00000001000000010000000100000001
-nan, -nan, -nan, -nan, -nan, // exp bits all 1, mantissa not 0
11111111111111111111111111111111 // sign bit is 1, negative

4.68413e-310, 4.68413e-310, 6.95306e-310, 4.94066e-324, 6.95306e-310, // garbage
0000000000000000010101100011101000110001000011010111000101010001
0000000000000000010101100011101000110001000011010111000000001000
0000000000000000011111111111111010010101010100100110010111001000
0, 0, 0, 0, 0,
0000000000000000000000000000000000000000000000000000000000000000
7.7486e-304, 7.7486e-304, 7.7486e-304, 7.7486e-304, 7.7486e-304,
0000000100000001000000010000000100000001000000010000000100000001
-nan, -nan, -nan, -nan, -nan, // sign bit 1, exp bits 1, mantissa not 0
1111111111111111111111111111111111111111111111111111111111111111

-nan, nan, nan, nan, nan, // garbage (Unnormal, invalid operands)
0000000000000000000000000000000100000000000000001111111111111111 // part 2
0000000000000000000000000000000000000000000000000000001010000000 // part 1
0000000000000000010101100011101000110001000011010100011111101000 // last bits
0000000000000000011111111111111010010101010100100110010010010000 // first
0000000000000000010101100011101000110001000011010100100110101101 // 127-64
0000000000000000000000000000000000000000000000000000000000000010 // 63-0
0, 0, 0, 0, 0, (sign bit 79 is 0, positive)
0000000000000000000000000000000000000000000000000000000000000000 // 78-64 (0)
0000000000000000000000000000000000000000000000000000000000000000 // 63-0 (0)
nan, nan, nan, nan, nan, // Unnormal, invalid operands (bit 79 is 0, positive)
0000000100000001000000010000000100000001000000010000000100000001 // 78-64 (0/1)
0000000100000001000000010000000100000001000000010000000100000001 // 63 (0)
-nan, -nan, -nan, -nan, -nan, // Quiet Not a Number (bit 79 is 1, negative)
1111111111111111111111111111111111111111111111111111111111111111 // 78-64 (1)
1111111111111111111111111111111111111111111111111111111111111111 // 63-0 (1)
*/





Notes:  See also Arrays.cpp (Exercise_3-26).

11110101010101000000000000000000 = ((-1)^1)*2^(2^1+2^3+2^5+2^6+2^7-127)*(1+2^(-1)+2^(-3)+2^(-5)) = (-1)*2^107*1.65625 ~ -2.68742e+32.
etc.









Chapter_3     Exercise_3-27 BACK_TO_TOP Exercise_3-29



Comments

Popular posts from this blog

Contents