Using Omron D6T-8L-09 H sensor we measure human temperature incorrectly - sensors

For example; I'm measuring my body temperature. The value I read is (tP [2] + tP [3] * 256) = 182 or 181. Because MSB bytes always come at 0. But sensor body temperature is OK, not wrong.
bus.write_byte(DEVICE_ADDRESS, 0x02)
bus.write_byte(DEVICE_ADDRESS, 0x00)
bus.write_byte(DEVICE_ADDRESS, 0x01)
bus.write_byte(DEVICE_ADDRESS, 0xEE)
bus.write_byte(DEVICE_ADDRESS, 0x05)
bus.write_byte(DEVICE_ADDRESS, 0x90)
bus.write_byte(DEVICE_ADDRESS, 0x3A)
bus.write_byte(DEVICE_ADDRESS, 0xB8)
bus.write_byte(DEVICE_ADDRESS, 0x03)
bus.write_byte(DEVICE_ADDRESS, 0x00)
bus.write_byte(DEVICE_ADDRESS, 0x03)
bus.write_byte(DEVICE_ADDRESS, 0x8B)
bus.write_byte(DEVICE_ADDRESS, 0x03)
bus.write_byte(DEVICE_ADDRESS, 0x00)
bus.write_byte(DEVICE_ADDRESS, 0x07)
bus.write_byte(DEVICE_ADDRESS, 0x97)
bus.write_byte(DEVICE_ADDRESS, 0x02)
bus.write_byte(DEVICE_ADDRESS, 0x00)
bus.write_byte(DEVICE_ADDRESS, 0x00)
bus.write_byte(DEVICE_ADDRESS, 0xE9)
a = bus.read_i2c_block_data(DEVICE_ADDRESS, 0x05, 2)
b = bus.read_i2c_block_data(DEVICE_ADDRESS, 0x03, 2)
readbuff = bus.read_i2c_block_data(DEVICE_ADDRESS, 0x4C, 19)
bus.close()
tPTAT = 256 * readbuff[1] + readbuff[0]
tP[0] = ((readbuff[3] * 256) + readbuff[2])
.
.
tP[7] = ((readbuff[17] * 256) + readbuff[16])
tPEC = readbuff[18]

As per the datasheet of D6T-8L:
reference_temprature = 256*readbuff[1] + readbuff[0];
int i = 0;
int j = 0;
for( i = 2; i<16; i = i +2) {
temprature[j] = (256*readbuff[i+1] + readbuff[i])/10.0;
j++;
}
packet_error_check = readbuff[i];
Please follow the reference circuit from datasheet and validate the PEC. Here is another code sample: Github

Related

Why the output goes wrong when using pthread_join?

I am still learning about threads and I was trying to solve this problem in my code, when I am putting the pthread_join(thread[i],NULL) outside the loop that is creating the threads it always gives me wrong output and Thread with ID = 0 will not work(call the median func) and the last thread will work two times, for better understanding see the output below:
ThreadID= 0, startRow= 0, endRow= 0 // first thread doesn't call the median func
ThreadID= 1, startRow= 1, endRow= 1
ThreadID 1 numOfBright 0 numOfDark 1 numOfNormal 4
ThreadID= 2, startRow= 2, endRow= 2
ThreadID 2 numOfBright 0 numOfDark 1 numOfNormal 4
ThreadID= 3, startRow= 3, endRow= 3
ThreadID 3 numOfBright 0 numOfDark 0 numOfNormal 5
ThreadID= 4, startRow= 4, endRow= 4
ThreadID 4 numOfBright 0 numOfDark 5 numOfNormal 0
ThreadID 4 numOfBright 0 numOfDark 5 numOfNormal 0 // last thread is calling the median func two times.
This is the part of the code that prints the start and end row of each thread.
pthread_t* threads = new pthread_t[num_threads];
struct Th_Range* RANGE = (struct Th_Range*)malloc(sizeof(struct Th_Range*));
int thread_status;
RANGE->SizeOfImage = r; // 2d array with size (n*n) so rows(r) = columns(c)
if (n == num_threads) { //rows = num of threads then every thread will work in a single row
for (int i = 0; i < num_threads; i++) {
RANGE->ThreadId = i;
RANGE->StartRow = RANGE->EndRow = i;
cout << "ThreadID= " << i << ", startRow= " << RANGE->StartRow << ", endRow= " << RANGE->EndRow << endl;
thread_status = pthread_create(&threads[i], NULL, Median, RANGE);
if (thread_status)
exit(-1);
} //for loop ends here
for (int i = 0; i < num_threads; i++)
pthread_join(threads[i],NULL);
} //end of if statement
Here is the part of the code if needed with the median function and the above if statement.
#include <iostream>
#include <bits/stdc++.h>
#include <pthread.h>
pthread_mutex_t Lock;
pthread_mutex_t Pixels;
pthread_mutex_t Pixels2;
using namespace std;
int numOfBright, numOfDark, numOfNormal;
int** Oimage, ** Fimage; //original and filtered image
struct Th_Range {
int SizeOfImage;
int StartRow;
int EndRow;
int ThreadId;
};
void* Median(void* par)
{
struct Th_Range* Num = (struct Th_Range*)par;
int StartRow = Num->StartRow;
int EndRow = Num->EndRow;
int Size = Num->SizeOfImage;
int Neighbour[9] = { 0 };
int dark = 0, bright = 0, normal = 0;
if (EndRow == StartRow)
EndRow += 2;
else
EndRow++;
for (int i = StartRow +1; i < EndRow ; i++)
{
for (int j = 1; j < Size - 1; j++)
{
Neighbour[0] = Oimage[i - 1][j - 1];
Neighbour[1] = Oimage[i - 1][j];
Neighbour[2] = Oimage[i - 1][j + 1];
Neighbour[3] = Oimage[i][j - 1];
Neighbour[4] = Oimage[i][j];
Neighbour[5] = Oimage[i][j + 1];
Neighbour[6] = Oimage[i + 1][j - 1];
Neighbour[7] = Oimage[i + 1][j];
Neighbour[8] = Oimage[i + 1][j + 1];
pthread_mutex_lock(&Pixels); //it can be moved only to lock the Fimage and the numOfBright or any other global variables
sort(Neighbour, Neighbour + 9);
Fimage[i][j] = Neighbour[4];
if (Neighbour[4] > 200) {
bright++;
numOfBright++;
}
else if (Neighbour[4] < 50) {
dark++;
numOfDark++;
}
else {
normal++;
numOfNormal++;
}
pthread_mutex_unlock(&Pixels);
}
}
pthread_mutex_lock(&Pixels2); //when I try to remove this lock the output gets interrupted
cout << "ThreadID " << Num->ThreadId << " numOfBright " << bright << " numOfDark " << dark << " numOfNormal " << normal<<endl;
pthread_mutex_unlock(&Pixels2);
pthread_exit(NULL);
}
int main(int argc, char* argv[])
{
int num_threads, n, r, c; // n is the size of the matrix r and c are rows and columns
numOfNormal = numOfDark = numOfBright = 0;
if (argc >= 2)
num_threads = atoi(argv[1]);
else
exit(-1);
ifstream cin("input.txt");
cin >> n;
r = c = n + 2;
Oimage = new int* [r]();
Fimage = new int* [r]();
for (int i = 0; i < c; i++)
{
Oimage[i] = new int[c]();
Fimage[i] = new int[c]();
}
for (int i = 1; i < r - 1; i++)
for (int j = 1; j < c - 1; j++)
cin >> Oimage[i][j];
pthread_t* threads = new pthread_t[num_threads];
struct Th_Range* RANGE = (struct Th_Range*)malloc(sizeof(struct Th_Range*));
RANGE->SizeOfImage = r;
if (n == num_threads) { //rows = num of threads then every thread will work in a single row
//n+2
int thread_status;
for (int i = 0; i < num_threads; i++) {
RANGE->ThreadId = i;
RANGE->StartRow = RANGE->EndRow = i;
// pthread_mutex_lock(&Lock);
cout << "ThreadID= " << i << ", startRow= " << RANGE->StartRow << ", endRow= " << RANGE->EndRow << endl;
thread_status = pthread_create(&threads[i], NULL, Median, RANGE);
if (thread_status)
exit(-1);
}
}
I tried to move pthread_join inside the loop of pthread_create it gives a correct output but of course it is a wrong solution. I have no idea what to do next. Thanks in advance
Maybe you should use #include
or (using namespace sff) it must work

Linux scsi ata cmd write or read sometimes work and sometimes didn't work when transfer length is over 1345

My code is as follows:
unsigned char cmd[16];
cmd[0] = WRITE_16;
//lba is start address
cmd[2] = (lba >> 54) & 0xFF;
cmd[3] = (lba >> 48) & 0xFF;
cmd[4] = (lba >> 40) & 0xFF;
cmd[5] = (lba >> 32) & 0xFF;
cmd[6] = (lba >> 24) & 0xFF;
cmd[7] = (lba >> 16) & 0xFF;
cmd[8] = (lba >> 8) & 0xFF;
cmd[9] = lba & 0xFF;
//len is transfer length
cmd[10] = (len >> 24) & 0xFF;
cmd[11] = (len >> 16) & 0xFF;
cmd[12] = (len >> 8) & 0xFF;
cmd[13] = len & 0xFF;
void* buffer;
buffer = malloc(len*512);
__u64 buffer_len = 512*len;
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(cmd);
io_hdr.mx.sb_len = sizeof(sense);
io_hdr.dxfer_direction = SG_DXFER_TO_FROM_DEV;
io_hdr.dxfer_len = buffer_len;
io_hdr.dxferp = buffer;
io_hdr.cmdp = cmd;
io_hdr.sbp = sense;
io_hdr.timeout = 30000;
ioctl(fd, SG_IO, &io_hdr);
If I send cmd transfer length over 1345, it sometimes work and sometimes it doesn't work. If thetransfer length grows up, the portion that doesn't work goes up too. There's no uart log or kernel log when cmd doesn't work.
ps. If cmd doesn't work, errno says 22(invalid argument)
You're not initializing the bytes in the SCSI CDB to zero, so sometimes there's trash in cmd[1], cmd[14], and cmd[15]. Add a call to memset up at the top, or initialize the array with = { };.
Also, I know a bunch of examples use this technique for initializing the command structure, but man, it's really going to drive you nuts. I recommend defining an __attribute__ ((packed)) structure for the CDB that uses bitfields.
Lastly, the line cmd[2] = (lba >> 54) & 0xFF; should shift lba by 56 bits, not 54 bits.

I2C communication using MSP432G2553 and HMC5883L

I am trying to interface my HMC5883L magnetometer with my MSP432G2553 to get continuous readings on x,y and z axis to provide orientation for a device.
I am having problem getting data using the i2c communication. I am trying to get the x,y and z data but I am not getting anything from my code. I would appreciate any feedback, I am new to the I2C communication.
I found a code online and have been using it and modifying it. Here is the code:
main code:
#include <msp430g2553.h>
#include "my_types.h"
#include "i2c.h"
#define M_PI 3.14159265358979323846264338327950288
int TXByteCtr;
unsigned char PRxData;
int Rx = 0;
char WHO_AM_I = 0x1E;
char itgAddress = 0x69;
const uchar setup_hmc5883[] = {0x00, 0x70};
const uchar gain_hmc5883[] = {0x01, 0xA0};
const uchar continuous_hmc5883[] = {0x02, 0x00};
const uchar base_hmc5883[] = {0x03};
char readBuffer [6];
void init_I2C(void);
void Transmit(void);
void Receive(void);
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
int x, y, z ;
float heading ;
float headingDegrees ;
P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0
P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0
BCSCTL1 = CALBC1_16MHZ ;
DCOCTL = CALDCO_16MHZ ;
init_I2C();
Rx = 0;
TXByteCtr = 1;
writei2c(0x3C,setup_hmc5883,2);
TXByteCtr = 1;
writei2c(0x3C,gain_hmc5883,2);
TXByteCtr = 1;
writei2c(0x3C,continuous_hmc5883,2);
while(1){
writei2c(0x3C, base_hmc5883, 1);
__delay_cycles(100000);
readi2c(0X3D, readBuffer, 6);
x = readBuffer[0] ;
x |= readBuffer[1] << 8 ;
z = readBuffer[2] ;
z |= readBuffer[3] << 8 ;
y = readBuffer[4] ;
y |= readBuffer[5] << 8 ;
heading = atan2(y, x);
if(heading < 0) heading += 2*M_PI;
headingDegrees = heading * 180/M_PI;
}
}
//-------------------------------------------------------------------------------
// The USCI_B0 data ISR is used to move received data from the I2C slave
// to the MSP430 memory. It is structured such that it can be used to receive
//-------------------------------------------------------------------------------
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
if(Rx == 1){ // Master Recieve?
PRxData = UCB0RXBUF; // Get RX data
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
else{ // Master Transmit
if (TXByteCtr) // Check TX byte counter
{
if ((IFG2 & UCB0TXIFG) || (IFG2 & UCB0RXIFG))
i2cDataInterruptService();
TXByteCtr--; // Decrement TX byte counter
if(!TXByteCtr)
{
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}
}
}
void init_I2C(void) {
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB0BR1 = 0;
UCB0I2CSA = itgAddress; // Slave Address is 069h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
IE2 |= UCB0RXIE + UCB0TXIE; //Enable RX and TX interrupt
}
i2c.c:
#include "i2c.h"
volatile char i2cBusy = 0;
volatile unsigned char i2cBufferLength = 0 ;
unsigned char * i2cBufferPtr ;
volatile char txDone = 1 ;
volatile char rxDone = 1 ;
void initi2c(unsigned int divider){
P1SEL |= BIT6 + BIT7 ;
P1SEL2 |= BIT6 + BIT7 ;
UCB0CTL1 |= UCSWRST ;
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC ;
UCB0CTL1 = UCSSEL_2 + UCSWRST ;
UCB0BR0 = divider & 0x00FF ;
UCB0BR1 = ((divider & 0xFF00) >> 8) ;
UCB0I2CSA = 0x069 ;
UCB0I2CIE = UCNACKIE | UCALIE;
UCB0CTL1 &= ~UCSWRST ;
IE2 |= UCB0TXIE | UCB0RXIE ;
}
char writei2c(unsigned char addr, unsigned char * data, unsigned char nbData){
UCB0I2CSA = addr ;
i2cBusy = 0 ;
i2cBufferPtr = data ;
i2cBufferLength = nbData ;
txDone = 0 ;
UCB0CTL1 |= UCTR + UCTXSTT;
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
//while(txDone == 0) ;
//return txDone ;
}
char readi2c(unsigned char addr, unsigned char * data, unsigned char nbData){
UCB0I2CSA = addr ;
i2cBusy = 0 ;
i2cBufferPtr = data ;
i2cBufferLength = nbData ;
rxDone = 0 ;
UCB0CTL1 &= ~UCTR;
UCB0CTL1 |= UCTXSTT;
while(UCB0CTL1 & UCTXSTT);
UCB0CTL1 |= UCTXSTP ;
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
while(rxDone == 0) ;
return rxDone ;
}
inline void i2cDataInterruptService(void){
if ((IFG2 & UCB0TXIFG) != 0 || (IFG2 & UCB0RXIFG) != 0){
if((UCB0CTL1 & UCTR) != 0){
if(i2cBusy >= i2cBufferLength){
UCB0CTL1 |= UCTXSTP ;
i2cBusy = 0 ;
txDone = 1 ;
IFG2 &= ~UCB0TXIFG;
}else{
UCB0TXBUF = i2cBufferPtr[i2cBusy] ;
i2cBusy ++ ;
}
}else{
if((i2cBufferLength - i2cBusy) == 1){ // may generate a repeated stop condition
UCB0CTL1 |= UCTXSTP ;
}
i2cBufferPtr[i2cBusy] = UCB0RXBUF;
i2cBusy ++ ;
if(i2cBusy >= i2cBufferLength){
i2cBusy = 0 ;
rxDone = 1 ;
}
}
}
}
inline void i2cErrorInterruptService(void){
if ((UCB0STAT & UCNACKIFG) != 0) {
UCB0CTL1 |= UCTXSTP;
UCB0STAT &= ~UCNACKIFG;
i2cBusy = -1;
txDone = -1 ;
rxDone = -1 ;
}else if ((UCB0STAT & UCALIE) != 0) {
UCB0CTL1 |= UCTXSTP;
UCB0STAT &= ~UCALIE;
i2cBusy = -1;
txDone = -1 ;
rxDone = -1 ;
}
}

How to multiply hex color codes?

I want to change color from 0x008000 (green) to 0x0000FF (blue).
If I multiply 0x008000 * 256 = 0x800000 (Google search acts as a calculator).
I need to find the correct multiplier so the result would be 0x0000FF.
To answer people below - I am doing this in order to make a color transition on a rectangle in pixi.js.
From what I've gathered, RGB color code is divided into 3 parts - red, green and blue in a scale of 0-FF expressed in hex, or 0-255 in decimal. But how to multiply correctly to get desired result?
If you want linear change from one color to another, i recommend something like this:
int startColor = 0x008000;
int endColor = 0x0000FF;
int startRed = (startColor >> 16) & 0xFF;
int startGreen = (startColor >> 8) & 0xFF;
int startBlue = startColor & 0xFF;
int endRed, endGreen, endBlue; //same code
int steps = 24;
int[] result = new int[steps];
for(int i=0; i<steps; i++) {
int newRed = ( (steps - 1 - i)*startRed + i*endRed ) / (steps - 1);
int newGreen, newBlue; //same code
result[i] = newRed << 16 | newGreen << 8 | newBlue;
}
This is for JavaScript:
var startColor = 0x008000;
var endColor = 0x0000FF;
var startRed = (startColor >> 16) & 0xFF;
var startGreen = (startColor >> 8) & 0xFF;
var startBlue = startColor & 0xFF;
var endRed = (endColor >> 16) & 0xFF;
var endGreen = (endColor >> 8) & 0xFF;
var endBlue = endColor & 0xFF;
var steps = 24;
var result = [];
for (var i = 0; i < steps; i++) {
var newRed = ((steps - 1 - i) * startRed + i * endRed) / (steps - 1);
var newGreen = ((steps - 1 - i) * startGreen + i * endGreen) / (steps - 1);
var newBlue = ((steps - 1 - i) * startBlue + i * endBlue) / (steps - 1);
var comb = newRed << 16 | newGreen << 8 | newBlue;
console.log(i + " -> " + comb.toString(16));
result.push(comb);
}
console.log(result);

Convert extended precision float (80-bit) to double (64-bit) in MSVC

What is the most portable and "right" way to do conversion from extended precision float (80-bit value, also known as long double in some compilers) to double (64-bit) in MSVC win32/win64?
MSVC currently (as of 2010) assumes that long double is double synonym.
I could probably write fld/fstp assembler pair in inline asm, but inline asm is not available for win64 code in MSVC. Do I need to move this assembler code to separate .asm file? Is that really so there are no good solution?
Just did this in x86 code...
.686P
.XMM
_TEXT SEGMENT
EXTRN __fltused:DWORD
PUBLIC _cvt80to64
PUBLIC _cvt64to80
_cvt80to64 PROC
mov eax, dword ptr [esp+4]
fld TBYTE PTR [eax]
ret 0
_cvt80to64 ENDP
_cvt64to80 PROC
mov eax, DWORD PTR [esp+12]
fld QWORD PTR [esp+4]
fstp TBYTE PTR [eax]
ret 0
_cvt64to80 ENDP
ENDIF
_TEXT ENDS
END
If your compiler / platform doesn't have native support for 80 bit floating point values, you have to decode the value yourself.
Assuming that the 80 bit float is stored within a byte buffer, located at a specific offset, you can do it like this:
float64 C_IOHandler::readFloat80(IColl<uint8> buffer, uint32 *ref_offset)
{
uint32 &offset = *ref_offset;
//80 bit floating point value according to the IEEE-754 specification and the Standard Apple Numeric Environment specification:
//1 bit sign, 15 bit exponent, 1 bit normalization indication, 63 bit mantissa
float64 sign;
if ((buffer[offset] & 0x80) == 0x00)
sign = 1;
else
sign = -1;
uint32 exponent = (((uint32)buffer[offset] & 0x7F) << 8) | (uint32)buffer[offset + 1];
uint64 mantissa = readUInt64BE(buffer, offset + 2);
//If the highest bit of the mantissa is set, then this is a normalized number.
float64 normalizeCorrection;
if ((mantissa & 0x8000000000000000) != 0x00)
normalizeCorrection = 1;
else
normalizeCorrection = 0;
mantissa &= 0x7FFFFFFFFFFFFFFF;
offset += 10;
//value = (-1) ^ s * (normalizeCorrection + m / 2 ^ 63) * 2 ^ (e - 16383)
return (sign * (normalizeCorrection + (float64)mantissa / ((uint64)1 << 63)) * g_Math->toPower(2, (int32)exponent - 16383));
}
This is how I did it, and it compiles fine with g++ 4.5.0. It of course isn't a very fast solution, but at least a functional one. This code should also be portable to different platforms, though I didn't try.
I've just written this one. It constructs an IEEE double number from IEEE extended precision number using bit operations. It takes the 10 byte extended precision number in little endian format:
typedef unsigned long long uint64;
double makeDoubleFromExtended(const unsigned char x[10])
{
int exponent = (((x[9] << 8) | x[8]) & 0x7FFF);
uint64 mantissa =
((uint64)x[7] << 56) | ((uint64)x[6] << 48) | ((uint64)x[5] << 40) | ((uint64)x[4] << 32) |
((uint64)x[3] << 24) | ((uint64)x[2] << 16) | ((uint64)x[1] << 8) | (uint64)x[0];
unsigned char d[8] = {0};
double result;
d[7] = x[9] & 0x80; /* Set sign. */
if ((exponent == 0x7FFF) || (exponent == 0))
{
/* Infinite, NaN or denormal */
if (exponent == 0x7FFF)
{
/* Infinite or NaN */
d[7] |= 0x7F;
d[6] = 0xF0;
}
else
{
/* Otherwise it's denormal. It cannot be represented as double. Translate as singed zero. */
memcpy(&result, d, 8);
return result;
}
}
else
{
/* Normal number. */
exponent = exponent - 0x3FFF + 0x03FF; /*< exponent for double precision. */
if (exponent <= -52) /*< Too small to represent. Translate as (signed) zero. */
{
memcpy(&result, d, 8);
return result;
}
else if (exponent < 0)
{
/* Denormal, exponent bits are already zero here. */
}
else if (exponent >= 0x7FF) /*< Too large to represent. Translate as infinite. */
{
d[7] |= 0x7F;
d[6] = 0xF0;
memset(d, 0x00, 6);
memcpy(&result, d, 8);
return result;
}
else
{
/* Representable number */
d[7] |= (exponent & 0x7F0) >> 4;
d[6] |= (exponent & 0xF) << 4;
}
}
/* Translate mantissa. */
mantissa >>= 11;
if (exponent < 0)
{
/* Denormal, further shifting is required here. */
mantissa >>= (-exponent + 1);
}
d[0] = mantissa & 0xFF;
d[1] = (mantissa >> 8) & 0xFF;
d[2] = (mantissa >> 16) & 0xFF;
d[3] = (mantissa >> 24) & 0xFF;
d[4] = (mantissa >> 32) & 0xFF;
d[5] = (mantissa >> 40) & 0xFF;
d[6] |= (mantissa >> 48) & 0x0F;
memcpy(&result, d, 8);
printf("Result: 0x%016llx", *(uint64*)(&result) );
return result;
}
Played with the given answers and ended up with this.
#include <cmath>
#include <limits>
#include <cassert>
#ifndef _M_X64
__inline __declspec(naked) double _cvt80to64(void* ) {
__asm {
// PUBLIC _cvt80to64 PROC
mov eax, dword ptr [esp+4]
fld TBYTE PTR [eax]
ret 0
// _cvt80to64 ENDP
}
}
#endif
#pragma pack(push)
#pragma pack(2)
typedef unsigned char tDouble80[10];
#pragma pack(pop)
typedef struct {
unsigned __int64 mantissa:64;
unsigned int exponent:15;
unsigned int sign:1;
} tDouble80Struct;
inline double convertDouble80(const tDouble80& val)
{
assert(10 == sizeof(tDouble80));
const tDouble80Struct* valStruct = reinterpret_cast<const tDouble80Struct*>(&val);
const unsigned int mask_exponent = (1 << 15) - 1;
const unsigned __int64 mantissa_high_highestbit = unsigned __int64(1) << 63;
const unsigned __int64 mask_mantissa = (unsigned __int64(1) << 63) - 1;
if (mask_exponent == valStruct->exponent) {
if(0 == valStruct->mantissa) {
return (0 != valStruct->sign) ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
}
// highest mantissa bit set means quiet NaN
return (0 != (mantissa_high_highestbit & valStruct->mantissa)) ? std::numeric_limits<double>::quiet_NaN() : std::numeric_limits<double>::signaling_NaN();
}
// 80 bit floating point value according to the IEEE-754 specification and
// the Standard Apple Numeric Environment specification:
// 1 bit sign, 15 bit exponent, 1 bit normalization indication, 63 bit mantissa
const double sign(valStruct->sign ? -1 : 1);
//If the highest bit of the mantissa is set, then this is a normalized number.
unsigned __int64 mantissa = valStruct->mantissa;
double normalizeCorrection = (mantissa & mantissa_high_highestbit) != 0 ? 1 : 0;
mantissa &= mask_mantissa;
//value = (-1) ^ s * (normalizeCorrection + m / 2 ^ 63) * 2 ^ (e - 16383)
return (sign * (normalizeCorrection + double(mantissa) / mantissa_high_highestbit) * pow(2.0, int(valStruct->exponent) - 16383));
}

Resources