Конвертировать C # double в Delphi Real48

4

Я нашел следующий вопрос Преобразовать Delphi Real48 в С# double, но я хочу пойти другим путем, С# в Delphi.

Кто-нибудь знает, как это можно сделать? Я пробовал обратное проектирование кода, но без большой удачи.

Update:

Я после кода С#, который возьмет двойной и преобразует его в Real48 (byte [] размера 6).

Спасибо

  • 0
    Какой язык конвертировать - Delphi или C #?
  • 1
    Если это будет Delphi, решение будет "MyReal48Var: = MyDoubleVar;" ;-)
Теги:
double

5 ответов

5

Я наткнулся на эту тему, ища тот же код. Вот что я написал:

public static byte [] Double2Real48(double d)
{
    byte [] r48 = new byte[6];
    byte [] da = BitConverter.GetBytes(d);

    for (int i = 0; i < r48.Length; i++)
        r48[i] = 0;

    //Copy the negative flag
    r48[5] |= (byte)(da[7] & 0x80);

    //Get the expoent
    byte b1 = (byte)(da[7] & 0x7f);
    ushort n = (ushort)(b1 << 4);
    byte b2 = (byte)(da[6] & 0xf0);
    b2 >>= 4;
    n |= b2;

    if (n == 0)
        return r48;

    byte ex = (byte)(n - 1023);
    r48[0] = (byte)(ex + 129);

    //Copy the Mantissa
    r48[5] |= (byte)((da[6] & 0x0f) << 3);//Get the last four bits
    r48[5] |= (byte)((da[5] & 0xe0) >> 5);//Get the first three bits

    r48[4]  = (byte)((da[5] & 0x1f) << 3);//Get the last 5 bits
    r48[4] |= (byte)((da[4] & 0xe0) >> 5);//Get the first three bits

    r48[3]  = (byte)((da[4] & 0x1f) << 3);//Get the last 5 bits
    r48[3] |= (byte)((da[3] & 0xe0) >> 5);//Get the first three bits

    r48[2]  = (byte)((da[3] & 0x1f) << 3);//Get the last 5 bits
    r48[2] |= (byte)((da[2] & 0xe0) >> 5);//Get the first three bits

    r48[1]  = (byte)((da[2] & 0x1f) << 3);//Get the last 5 bits
    r48[1] |= (byte)((da[1] & 0xe0) >> 5);//Get the first three bits

    return r48;

}

Real48 похож на IEEE 754 тем, что Мантисса будет одинаковой. Сдвиг бит необходим, чтобы получить Мантису в нужном месте.

Показатель Real48 имеет смещение 129, а двойник имеет смещение 1023.

Отрицательный флаг сохраняется в первом бите последнего байта.

Примечания: Я не думаю, что этот код будет работать на большой конечной машине. Он не проверяет наличие NAN или INF.

Вот код, который преобразует real48 в double. Он был перенесен из компилятора Free Pascal:

static double real2double(byte [] r)
{
    byte [] res = new byte[8];
    int exponent;

    //Return zero if the exponent is zero        
    if (r[0] == 0)
        return (double)0;

    //Copy Mantissa
    res[0] = 0;
    res[1] = (byte)(r[1] << 5);
    res[2] = (byte)((r[1] >> 3) | (r[2] << 5));
    res[3] = (byte)((r[2] >> 3) | (r[3] << 5));
    res[4] = (byte)((r[3] >> 3) | (r[4] << 5));
    res[5] = (byte)((r[4] >> 3) | ((r[5] & 0x7f) << 5));
    res[6] = (byte)((r[5] & 0x7f) >> 3);

    //Copy exponent
    //correct exponent
    exponent = (r[0] + (1023-129));
    res[6] = (byte)(res[6] | ((exponent & 0xf) << 4));
    res[7] = (byte)(exponent >> 4);

    //Set Sign
    res[7] = (byte)(res[7] | (r[5] & 0x80));
    return BitConverter.ToDouble(res, 0);  
}
1

Простейшим способом, если это возможно, было бы преобразовать его в строку, передать, а затем преобразовать обратно в Real48

1

Если вы знакомы с C (как вы пишете на С#, все должно быть хорошо), проверьте эту функцию. Перемещение его на С# не должно быть слишком сложным.

Это довольно уродливое, но необходимое, я думаю.

Ссылка: http://forums.ni.com/ni/board/message?board.id=60&message.id=3553

    enum prconverr double_to_real (double d, real *r)
    /* converts C double to Pascal real, returns error code */

{
    union doublearray da;
    unsigned x;

    da.d = d;

    /* check for 0.0 */
    if ((da.a[0] == 0x0000) &&
        (da.a[1] == 0x0000) &&
        (da.a[2] == 0x0000) &&
        /* ignore sign bit */
        ((da.a[3] & 0x7FFF) == 0x0000)) {
        /* exponent and significand are both 0, so value is 0.0 */
        (*r)[2] = (*r)[1] = (*r)[0] = 0x0000;
        /* sign bit is ignored ( -0.0 -> 0.0 ) */
        return prOK;
    }

    /* test for maximum exponent value */
    if ((da.a[3] & 0x7FF0) == 0x7FF0) {
        /* value is either Inf or NaN */
        if ((da.a[0] == 0x0000) &&
            (da.a[1] == 0x0000) &&
            (da.a[2] == 0x0000) &&
            ((da.a[3] & 0x000F) == 0x0000)) {
            /* significand is 0, so value is Inf */
            /* value becomes signed maximum real, */
            /* and error code prInf is returned */
            (*r)[1] = (*r)[0] = 0xFFFF;
            (*r)[2] = 0x7FFF |
                      (da.a[3] & 0x8000); /* retain sign bit */
            return prInf;
        } else {
            /* significand is not 0, so value is NaN */
            /* value becomes 0.0, and prNaN code is returned */
            /* sign bit is ignored (no negative NaN) */
            (*r)[2] = (*r)[1] = (*r)[0] = 0x0000;
            /* sign bit is ignored ( -NaN -> +NaN ) */
            return prNaN;
        }
    }

    /* round significand if necessary */
    if ((da.a[0] & 0x1000) == 0x1000) {
        /* significand 40th bit set, so round significand up */
        if ((da.a[0] & 0xE000) != 0xE000)
            /* room to increment 3 most significant bits */
            da.a[0] += 0x2000;
        else {
            /* carry bit to next element */
            da.a[0] = 0x0000;
            /* carry from 0th to 1st element */
            if (da.a[1] != 0xFFFF)
                da.a[1]++;
            else {
                da.a[1] = 0x0000;
                /* carry from 1st to 2nd element */
                if (da.a[2] != 0xFFFF)
                    da.a[2]++;
                else {
                    da.a[2] = 0x0000;
                    /* carry from 2nd to 3rd element */
                    /* significand may overflow into exponent */
                    /* exponent not full, so won't overflow */
                    da.a[3]++;
                }
            }
        }
    }

    /* get exponent for underflow/overflow tests */
    x = (da.a[3] & 0x7FF0) >> 4;

    /* test for underflow */
    if (x < 895) {
        /* value is below real range */
        (*r)[2] = (*r)[1] = (*r)[0] = 0x0000;
        if ((da.a[3] & 0x8000) == 0x8000)
            /* sign bit was set, so value was negative */
            return prNegUnderflow;
        else
            /* sign bit was not set */
            return prPosUnderflow;
    }

    /* test for overflow */
    if (x > 1149) {
        /* value is above real range */
        (*r)[1] = (*r)[0] = 0xFFFF;
        (*r)[2] = 0x7FFF | (da.a[3] & 0x8000); /* retain sign bit */
        return prOverflow;
    }

    /* value is within real range */
    (*r)[0] = (x - 894) |  /* re-bias exponent */
              ((da.a[0] & 0xE000) >> 5) |  /* begin significand */
              (da.a[1] << 11);
    (*r)[1] = (da.a[1] >> 5) |
              (da.a[2] << 11);
    (*r)[2] = (da.a[2] >> 5) |
              ((da.a[3] & 0x000F) << 11) |
              (da.a[3] & 0x8000);  /* copy sign bit */
    return prOK;

}
  • 0
    @ Seidr Я не понимаю код, который вы разместили, откуда он получает возвращаемые значения и как вы заполняете значения da в начале? Спасибо
  • 0
    Из того, что я вижу, переменная 'da' - это массив значений (я думаю, битов памяти), полученных из входных данных типа double. Для второго аргумента этой функции вы указываете POINTER для «реальной» переменной, которую вы определили до вызова этой функции. Выходные данные затем напрямую передаются в эту переменную. Как я уже сказал, это функция C, и поэтому потребуется модификация, чтобы она работала в C #. Я предоставил это просто как точку в правильном направлении. Видите ли, я не уверен насчет поддержки указателей в C #. Удачи
0

В C/С++

typedef struct {
   unsigned char exponent;  // 8 bites;
   unsigned long mantisaLo; // 32 of 39 bites
   unsigned char mantisaHi : 7, sign : 1;  // 7 of 39 bites
} T_Real48;

typedef struct {
   unsigned long mantisaLo; // 32 of 52 bites
   unsigned long mantisaHi:20, exponent: 11, sign : 1; // 20 of 52 bites
} T_Double64;

double doubleToReal48(double val)
{
  T_Real48 real48;
  T_Double64 *double64 = (T_Double64*) &val;

  real48.mantisaHi = double64->mantisaHi >> 13;
  real48.mantisaLo =(double64->mantisaLo >> 13) + ((double64->mantisaHi & 0x1FFF) << 19);
  real48.exponent  = double64->exponent - 894;
  real48.sign      = double64->sign;

  if (real48.exponent == 0) {
      real48.mantisaHi = 0;
      real48.mantisaLo = 0;
  }

  return *(double *)&real48;
}

double real48ToDouble(double val)
{
  T_Real48 *real48 = (T_Real48*) &val;
  T_Double64 double64;

  double64.mantisaHi = (real48->mantisaHi << 13) + (real48->mantisaLo >> 19);
  double64.mantisaLo = real48->mantisaLo << 13;
  double64.exponent  = real48->exponent + 894;
  double64.sign      = real48->sign;

  return *(double *)&double64;
}
0
double Double_Real48(double d)
{
  unsigned long long r48 = 0, tmp;

  tmp = *(long long *)&d;//m
  tmp/=0x20;
  tmp&=0x7FFFFFFFFF00;
  r48+=tmp;

  tmp = *(long long *)&d;//e
  tmp/=0x10000000000000;
  tmp-=894;
  tmp&=0xFF;
  if (tmp == 0) return 0.0;
  r48+=tmp;

  tmp = *(long long *)&d;//s
  tmp/=0x10000;
  tmp&=0x800000000000;
  r48+=tmp;

  return *(double *)&r48;
}

double Real48_Double(double r48)
{
  unsigned long long d = 0, tmp;

  tmp= *(long long *)&r48;//m
  tmp&=0x7FFFFFFFFF00;
  tmp*=0x20;
  d+=tmp;

  tmp= *(long long *)&r48;//e
  tmp&=0xFF;
  if (tmp == 0) return 0.0;
  tmp+=894;
  tmp*=0x10000000000000;
  d+=tmp;

  tmp= *(long long *)&r48;//s
  tmp&=0x800000000000;
  tmp*=0x10000;
  d+=tmp;

  return *(double *)&d;
}
  • 0
    С тех пор stdcall dll обычно real48 6 байтов обрабатывается как 8 байтов. Соответственно, мы даже не можем отправить тип конверсии Long Long. изменяя соответствующим образом вызванный прототип функции.
  • 0
    unsigned long long Double_Real48(double d) {unsigned long long r48 = 0, ...... return r48; }

Ещё вопросы

Сообщество Overcoder
Наверх
Меню