我正在尝试转换存储为int的十六进制值,并使用IEEE 32位规则将它们转换为浮点数。我特别努力为尾数和指数获得正确的值。十六进制存储在十六进制文件中。我希望有四位重要人物。以下是我的代码。
#include<mpi.h>
#include<stdio.h>
#include<stdlib.h>
int WhichSize(int mpiId, int numProc, int tam);
int main(int argc, char *argv[]){
int i;
int localSize;
int numProc;
int myid;
int leftProc;
int rightProc;
int * myArray;
int fullDomainSize = 16;
MPI_Request request;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numProc);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// Lets get each partition size.
localSize = WhichSize(myid, numProc, fullDomainSize);
// Allocate arrays acording to proc number.
if(numProc == 1){
//printf("Allocating Array for serial usage\n");
myArray = (int*)malloc(localSize*sizeof(int));
} else if(numProc == 2) {
//printf("Allocating Array for 2 proc usage\n");
myArray = (int*)malloc((localSize+ 1)*sizeof(int));
} else if(numProc > 2) {
if (myid == 0 || myid == numProc - 1){
//printf("Allocating array for boundary nodes usage\n");
myArray = (int*)malloc((localSize+ 1)*sizeof(int));
} else {
//printf("Allocating array for inner nodes usage\n");
myArray = (int*)malloc((localSize+ 2)*sizeof(int));
}
}
// Now we will fill the arrays with a dummy value 123. For the
// boundaries (ghosts) we will fill than with 80. Just to differe
// ntiate.
if(numProc == 1){
//printf("----------------------------------------\n");
//printf("Filling the serial array with values... \n");
for (i = 0; i<localSize; i++){
myArray[i] = 123;
}
} else if(numProc == 2) {
////printf("------------------------------------------------\n");
//printf("Filling array for two proc usage with values... \n");
for (i = 0; i<localSize; i++){
myArray[i] = 123;
}
// ghost.
myArray[localSize+1] = 8;
} else if(numProc > 2) {
if (myid == 0 || myid == numProc - 1){
//printf("--------------------------------------------------\n");
//printf("Filling boundary node arrays usage with values... \n");
for (i = 0; i<localSize; i++){
myArray[i] = 123;
}
// ghosts.
myArray[localSize+1] = 8;
} else {
//printf("--------------------------------------------------\n");
//printf("Filling inner node arrays usage with values... \n");
for (i = 0; i<localSize; i++){
myArray[i] = 123;
}
// ghosts.
myArray[localSize+1] = 8;
myArray[0] = 8;
}
}
// Now lets comunicate the ghosts with MPI_Sendrecv().
if(numProc == 1){
//printf("Serial usage, no ghost to comunicate \n");
} else if(numProc == 2) {
if (myid == 0){
//printf("Sending ghost value from proc %d to %d\n", myid, myid + 1);
MPI_Isend(&myArray[localSize+1],
1,
MPI_INT,
1,
12345,
MPI_COMM_WORLD,
&request);
} else if (myid == 1) {
//printf("Receiving ghost value from proc %d to %d\n", myid-1, myid);
MPI_Irecv(&myArray[localSize+1],
1,
MPI_INT,
0,
12345,
MPI_COMM_WORLD,
&request);
}
} else if(numProc > 2) {
if (myid == 0){
rightProc = myid + 1;
if (myid == 0){
//printf("-------------------------------\n");
//printf("Communicating Boundary ghosts !\n");
//printf("-------------------------------\n");
//printf("Sending ghost value from proc %d to %d\n", myid, myid + 1);
MPI_Isend(&myArray[localSize+1],
1,
MPI_INT,
rightProc,
12345,
MPI_COMM_WORLD,
&request);
} else if (myid == rightProc) {
//printf("Receiving ghost value from proc %d to %d\n", myid-1, myid);
MPI_Irecv(&myArray[localSize+1],
1,
MPI_INT,
0,
12345,
MPI_COMM_WORLD,
&request);
}
} else if (myid == numProc - 1) {
leftProc = myid - 1;
if (myid == numProc - 1){
//printf("-------------------------------\n");
//printf("Communicating Boundary ghosts !\n");
//printf("-------------------------------\n");
////printf("Sending ghost value from proc %d to %d\n", myid, myid + 1);
MPI_Isend(&myArray[localSize+1],
1,
MPI_INT,
leftProc,
12345,
MPI_COMM_WORLD,
&request);
} else if (myid == leftProc) {
rightProc = myid + 1;
//printf("Receiving ghost value from proc %d to %d\n", myid-1, myid);
MPI_Irecv(&myArray[localSize+1],
1,
MPI_INT,
rightProc,
12345,
MPI_COMM_WORLD,
&request);
}
} else {
//printf("-------------------------------\n");
//printf("Communicating Inner ghosts baby\n");
//printf("-------------------------------\n");
leftProc = myid - 1;
rightProc = myid + 1;
// Communicate tail ghost.
if (myid == leftProc) {
MPI_Isend(&myArray[localSize+1],
1,
MPI_INT,
rightProc,
12345,
MPI_COMM_WORLD,
&request);
} else if (myid == rightProc){
MPI_Irecv(&myArray[localSize+1],
1,
MPI_INT,
leftProc,
12345,
MPI_COMM_WORLD,
&request);
}
// Communicate head ghost.
if (myid == leftProc) {
MPI_Isend(&myArray[0],
1,
MPI_INT,
rightProc,
12345,
MPI_COMM_WORLD,
&request);
} else if (myid == rightProc){
MPI_Irecv(&myArray[0],
1,
MPI_INT,
leftProc,
12345,
MPI_COMM_WORLD,
&request);
}
}
}
// Now I Want to see if the ghosts are in place !.
if (myid == 0){
printf("The ghost value is: %d\n", myArray[localSize + 1]);
} else if (myid == numProc - 1){
printf("The ghost value is: %d\n", myArray[0]);
} else {
printf("The head ghost is: %d\n", myArray[0]);
printf("The tail ghost is: %d\n", myArray[localSize + 1]);
}
MPI_Finalize();
exit(0);
}
int WhichSize(int mpiId, int numProc, int tam){
double resto;
int tamLocal;
tamLocal = tam / numProc;
resto = tam - tamLocal*numProc;
if (mpiId < resto) tamLocal = tamLocal + 1;
return tamLocal;
}
}
答案 0 :(得分:2)
我怀疑你的意思是{/ 1}}
^
意味着&#34;以及#34;的力量。在C或C ++中没有这样的运算符。 mantissa2 = m1 * (2 ^ -1) + m2*(2 ^ -2) + m3*(2 ^ -3) + m4*(2 ^ -4);
运算符是逐位XOR运算符。
答案 1 :(得分:1)
我们需要转换IEEE-754单精度和双精度数字(使用32位和64位编码)。我们使用的C编译器具有一组受限制的函数,最终开发了以下函数(可以使用任何on-line C compiler对其进行轻松测试):
#include <stdio.h>
#include <math.h>
double ConvertNumberToFloat(unsigned long number, int isDoublePrecision)
{
int mantissaShift = isDoublePrecision ? 52 : 23;
unsigned long exponentMask = isDoublePrecision ? 0x7FF0000000000000 : 0x7f800000;
int bias = isDoublePrecision ? 1023 : 127;
int signShift = isDoublePrecision ? 63 : 31;
int sign = !((number >> signShift) & 0x01);
int exponent = ((number & exponentMask) >> mantissaShift) - bias;
int power = -1;
double total = 0.0;
for ( int i = 0; i < mantissaShift; i++ )
{
int calc = (number >> (mantissaShift-i-1)) & 0x01;
total += calc * pow(2.0, power);
power--;
}
total += 1.0;
double value = sign * pow(2.0, exponent) * total;
return value;
}
float GetSinglePrecision(unsigned int number)
{
return (float)ConvertNumberToFloat(number, 0);
}
double GetDoublePrecision(unsigned long number)
{
return ConvertNumberToFloat(number, 1);
}
int main()
{
unsigned int singleValue = 0x40490FDB; // 3.141592...
float singlePrecision = GetSinglePrecision(singleValue);
printf("IEEE754 Single (from 32bit 0x%08X): %.7f\n",singleValue,singlePrecision);
unsigned long doubleValue = 0x400921FB54442D18; // 3.141592653589793...
double doublePrecision = GetDoublePrecision(doubleValue);
printf("IEEE754 Double (from 64bit 0x%016lX): %.16f\n",doubleValue,doublePrecision);
}
答案 2 :(得分:0)
考虑到您的CPU遵循IEEE标准,您也可以使用union
。像这样的东西
union
{
int num;
float fnum;
} my_union;
然后将整数值存储到my_union.num
中,并通过获取my_union.fnum
将其读作浮动。
答案 3 :(得分:0)
您的代码中存在许多非常基本错误。
最明显的是使用^
重复使用&#34;&#34;的权力。 ^
是XOR运算符,对于&#34; power&#34;您必须使用pow(base, exponent)
中的math.h
功能。
接下来,&#34;我想要有四位重要人物&#34; (大概是尾数),但你只提取了四个位。四位只能编码0..15
,大约是一个半位。要获得四位有效数字,您至少需要log(10,000)/ log(2)≈13.288,或至少14位(但最好是17位,因此您可以得到一个完整的额外数字以获得更好的舍入)。 / p>
您为sign
提取错误的位,然后以错误的方式使用它。是的,如果是0
然后是sign = 1
,如果是1
,那么sign = -1
,但是你在最终计算中使用
value = (-1^sign) * ...
(同样使用^
,尽管偶数pow
在这里没有任何意义)。您应该立即使用sign * ..
。
exponent
被声明为unsigned int
,但对于负值则失败。 signed
需要pow(2, exponent)
(已从(2 ^ exponent)
更正)。
从积极的方面来说,(1+mantissa2)
确实是正确的。
将所有这些要点放在一起,并忽略了实际上只要求4位有效数字的事实,我得到以下代码。请注意,为了方便起见,我重新排列了初始位移和提取 - 我将mantissa
移至 left ,而不是右移,因此我可以在计算中对0
进行测试。
(啊,我错过了!)直接使用sign
不起作用,因为它被声明为unsigned int
。因此,如果您认为值为-1
,则它实际上会获得值4294967295
(更精确:来自UINT_MAX
的{{1}}的值)。
摆脱这种情况的最简单方法不是乘以limits.h
而只测试它,如果设置则取消sign
。
value
通过上述内容,您可以获得float floatizeMe (unsigned int myNumba )
{
//// myNumba comes in as 32 bits or 8 byte
unsigned int sign = myNumba >>31;
signed int exponent = ((myNumba >> 23) & 0xff) - 0x7F;
unsigned int mantissa = myNumba << 9;
float value = 0;
float mantissa2;
cout << endl << "input is : " << hex << myNumba << endl;
cout << endl << "mantissa is : " << hex << mantissa << endl;
value = 0.5f;
mantissa2 = 0.0f;
while (mantissa)
{
if (mantissa & 0x80000000)
mantissa2 += value;
mantissa <<= 1;
value *= 0.5f;
}
cout << "\nsign is: " << sign << endl;
cout << "exponent is : " << hex << exponent << endl;
cout << "mantissa 2 is : " << mantissa2 << endl;
/* REMOVE:
if above this number it is negative
if ( sign == 1)
sign = -1;
// if above this number it is positive
else {
sign = 1;
} */
/* value = sign * (1.0f + mantissa2) * (pow (2, exponent)); */
value = (1.0f + mantissa2) * (pow (2, exponent));
if (sign) value = -value;
cout << dec << "Float value is: " << value << "\n\n\n";
return value;
}
(0.2000000030)和0x3e4ccccd
(3.1415927410)等值的正确结果。
如果你的输入已经是IEEE-754格式(尽管是十六进制格式),那么所有的说法和完成,那么一个简单的演员应该就够了。
答案 4 :(得分:0)
只需执行以下操作(但首先确保将字节读入整数时,您具有正确的字节序):
float int_bits_to_float(int32_t ieee754_bits) {
float flt;
*((int*) &flt) = ieee754_bits;
return flt;
}
对我有用...当然,这假设float
具有32位,并且在您的体系结构上采用IEEE754格式(几乎总是这样)。
答案 5 :(得分:-1)
除了更简单之外,这也避免了任何舍入/精度错误。
float value = reinterpret_cast<float&>(myNumba)
如果您仍想单独检查部件,请在之后使用库函数std::frexp
。如果您不喜欢类型惩罚,至少使用std::ldexp
来应用指数而不是您的显式数学,这很容易受到舍入/精度错误和溢出的影响。
这两者的替代方法是使用联合类型,如this answer中所述。