sane.h intel mac equivalent in C?

Discussion in 'Mac Programming' started by subsonix, Jan 11, 2009.

  1. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #1
    Hi,

    I have come across an old header called sane.h. From (Standard Apple
    Numeric Environment [SANE]) with different data types, the data type I´m after is called 'extended' and is a 80 bit floating point value. My compiler don´t know what I´m talking about.

    So what would be an equivalent to the 'extended' data type in C on a intel mac?
     
  2. Guiyon macrumors 6502a

    Joined:
    Mar 19, 2008
    Location:
    North Shore, MA
    #2
    I would assume you're probably looking for the 'long double' type.
     
  3. subsonix thread starter macrumors 68040

    Joined:
    Feb 2, 2008
    #3
    Hey, thanks for that. Forget about the thread.

    Is there a way to get the memory content of a long double into a char array using C? It´s a 128bit value.
     
  4. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #4
    Code:
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
      long double myLd = 97832.932L;
      unsigned char *charList = (unsigned char *)&myLd;
      int len = sizeof(myLd);
      int pos = 0;
      int intVal = 0;
    
      for(pos = 0; pos < len; pos++) {
        intVal=(int)charList[pos];  
        printf("Byte %d of myLd as digits: %d\n",pos,intVal);
      }
    
      return 0;
    }
    
    I wouldn't recommend this, but it works. Printing as chars is probably a bad idea, as characters above 127 are extended ascii. On my platform long double was only 96 bits (only the first 80 are used for storage, the last 16 are just for alignment), so don't assume 128, use sizeof.

    -Lee
     
  5. subsonix thread starter macrumors 68040

    Joined:
    Feb 2, 2008
    #5
    Thanks! I tried to use the code to write the string to disk but then the values came out differently in hexdump, any idea what the issue might be? sizeof gave 16 btw. I need to somehow restrict the size to 10 bytes, perhaps there are some other solution than using an array.
     
  6. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #6
    So i just ran a test, and it looks like the long double on the version of OS X I am using is 16 bytes, but 6 are being used for padding, to get 16-byte alignment (my guess, 12 bytes would give 4-byte alignment). What that means is the "business" is only the first 10 bytes, which is what you were looking for.

    Now i think you should describe what you actually want to do. if you need to store long doubles to disk, and this doesn't need to be used on multiple platforms, you should just write them out in their native format. There's no need to use a character array, and try to write that out in ascii. If you need the values to be readable on other platforms, you'll probably want to go with JSON, XML, etc. for your data storage.

    What are you trying to achieve? There may be a easier, cleaner, faster, better, etc. way to do it.

    -Lee
     
  7. subsonix thread starter macrumors 68040

    Joined:
    Feb 2, 2008
    #7
    I´m trying to create a file header. This particulary field is 10 byte in length and a float. The data type is reffered to as extended belonging to sane.h, this data type doesn´t seem to exist, or have been replaced by the long double. Which shouldn´t matter if the space was of no concern. I could use a smaller data type and pad it manually to get ten bytes but then it is represented differently.
     
  8. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #8
    So there's some fixed-width field file format you are trying to reproduce? If so, i would try to set up a struct with the format. For some things like this, you might need to used a char list to get the right number of bytes, then memcpy in the leading N bytes from another type (like the first 10 bytes of these long doubles). You can then write out the struct to the file using binary I/O, read back into the struct, etc. I would say you should just write a routine that takes the "full" data elements, formats the struct, writes the struct to disk, then an alternate routine that will read the struct back up, and copy from the various types back to usable, in-memory items.

    Also, are you sure that the byte-order the file needs to be in matches the endianness of your platform?

    -Lee
     
  9. subsonix thread starter macrumors 68040

    Joined:
    Feb 2, 2008
    #9
    I´m trying to make a converter and what I have so far works, but with restricted conditions for the input file. At the moment I´m using an int to hold the value and pad the rest of the bits to reach 10 bytes in length. There is also the part of the exponent and signed bit which is just written into the struct for now. nedless to say, If I fed a file with a different value into this section the exponent and signed bit would make no sense at all and the file would be corupt.

    BTW this is not a problem that needs a solution, I´m doing this entirely to learn to program.
     
  10. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #10
    I can't say that I understood this clearly, but long double is what you want. The first 80 bits of your long double will be the value you need.

    -Lee
     
  11. subsonix thread starter macrumors 68040

    Joined:
    Feb 2, 2008
    #11
    Ok sorry, I´m reading in a file, converts its format to another format. The long double seems to store it´s content in the middle bytes BTW. This is what a long double with the value 44100 looks like after it´s been written to disk.

    Code:
    00 00 00 00 00 00 44 ac  0e 40 00 00 00 00 00 00
    
    44ac is the value and 0e40 is the exponent and signed bit I suppose.
     
  12. subsonix thread starter macrumors 68040

    Joined:
    Feb 2, 2008
    #12
    Lee, couldn´t the code you posted be used to achive this though? I have a hard time to get casting and pointers right still, I always manage to make some syntactic errors.

    Thanks for your help, appreciated.
     
  13. subsonix thread starter macrumors 68040

    Joined:
    Feb 2, 2008
    #13
    Memcpy did the trick, got a warning first but I forgot to include string.h.
     
  14. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #14
    Just so you're clear (are you working with AIF? Is this the sampling rate?), it's not the "middle" bytes that are storing things, you just have a very, very small significand relative to the size allowed. First things first, we have to reverse the byte order because of the endianness of x86. While we're at it, we'll ignore the padding of the last 6 bytes. This yields:
    Code:
    40 0E AC 44 00 00 00 00 00 00
    in binary:
    Code:
    01000000 00001110 10101100 01000100 00000000 00000000 00000000 00000000 00000000 00000000
    The format is:
    bit 79 is the sign bit. In this case, this is 0.

    bits 64-78 are the exponent, offset by 16383. This is:
    100000000001110
    or
    16398-16383=15

    bits 0-63 are the significand, in this case:
    1.0101100010001

    So we raise -1 to the sign bit, giving us 1. We then shift the decimal of the significand by the value of the exponent, yielding:
    1010110001000100.0
    Multiply times 1 for the sign, and convert to decimal, and we get:
    44100.0

    It seems easiest to just keep the constants for "standard" sampling rates as literals in your code. I'm sure you COULD have an arbitrary rate, but generally things stick to ~6 rates that you could easily just encode once, then always just have constant unsigned char arrays with those values.

    -Lee
     
  15. subsonix thread starter macrumors 68040

    Joined:
    Feb 2, 2008
    #15
    As I said, the program already works, I have taken care of endianess, it´s very obvious if you dont. What I meant with the middle bytes was its not stored from the lowest address as with the extended data type in sane.h, the data have six bytes with zero in them on each side, so in that sence it is the midle.

    I have made a function that reads the sample rate field of the file I wan´t to convert in to a long double. I then copy the first ten bytes into a char array, copy the end to a short, perform endian conversion andcopy to the begining.
     

Share This Page