Thứ Sáu, 28 tháng 12, 2012

Lập trình Android cho những người mới bắt đầu

Giới thiệu với các bạn một cuốn sách phù hợp cho việc tìm hiểu thế giới Android. Cuốn sách có tên "Hello, Android - Introducing Google's Mobile Development Platform. Không những giới thiệu những khái niệm mới của Android so với lập trình cũ, sách còn có một ứng dụng thực tiễn giúp ta tiếp cận nhanh hơn. Source code đầy đủ và hoàn toàn "free" :) Mình xin upload một chương của sách, nếu cần mọi việc cứ Google và download về.

















Thứ Năm, 31 tháng 5, 2012

ĐỌC GHI MỘT TẬP TIN NHỊ PHÂN CÓ CẤU TRÚC DỄ DÀNG VỚI C#


THAM KHẢO: http://weblogs.asp.net/ralfw/archive/2006/03/04/439580.aspx 


Easy high speed reading/writing of structured binary files using C#

Thật không may là không đơn giản như C / C + +. Đây là cách bạn có thể đọc thẻ ID3v1 từ một tập tin MP3 từ C/C++:
struct ID3v1Tag
{
   char tag[3]; // == "TAG"
   char title[30];
   ...
};
ID3v1Tag t;
FILE *f = fopen("mysong.mp3", "r");
fseek(f, -128, SEEK_END);
fread(&t, 1, 128, f);
printf("%.30s\n", t.title);
fclose(f);
Bây giờ, nếu bạn muốn thực hiện tương tự với C # ... nó sẽ không dễ dàng . Lý do: bạn không thể đọc dữ liệu từ một tập tin (stream) trực tiếp vào một cấu trúc. Stream luôn luôn đòi hỏi một byte Array để chứa kết quả đọc được. Hoặc nếu bạn sử dụng phương thức BinaryReader theReadBytes() cũngtrả về một  byte Array. Trong bất kỳ trường hợp nào các dữ liệu đọc vào một mảng byte cần phải được sao chép vào các Struct.
Cách 1: dùng Marshal.PtrToStructure() , và cách khác đơn giản hơn là dùng unsafe assignment như sau:
[StructLayout(LayoutKind.Sequential, Pack=1)]
unsafe struct ID3v1Tag
{
    ...
    public ID3v1Tag(byte[] data)
    {
       fixed (byte* pData = data)
       {
           this = *(ID3v1Tag*)pData;
       }
    }
}

Hoặc bạn có thể đọc dữ liệu từ một dòng đầu vào trong khối nhỏ bằng cách sử dụng một BinaryReader, có nghĩa là bạn tách các dữ liệu vào mỗi trường bằng tay.Điều này tránh sao chép thêm dữ liệu, nhưng đòi hỏi nhiều nỗ lực. Đây là cách đọc ghi dữ liệu nhị phân bình thường của C# (managed code)

Tuy nhiên, do một khách hàng yêu cầu, tôi đã bắt đầu suy nghĩ về cách này. Khách hàng cần phải chuyển C++ tương tác lớn với các tập tin nhị phân thành C #.Các phương pháp tiếp cận được tìm thấy trong các tài liệu lập trình, mặc dù vậy quá chậm theo yêu cầu của khách hàng. Truy suất dữ liệu bên ngoài làm chậm hiệu quả của chương trình. Do đó, anh ta giữ lại các thành phần cần thiết của C++ đê được hưởng lợi từ ngôn ngữ lập trình này trong việc truy cập dữ liệu.
Tôi cảm thấy bị thách thức bởi vấn đề này. Và đây là giải pháp của tôi: Dễ dàng đọc / ghi dữ liệu nhị phân có cấu trúc bằng cách sử dụng C # 2.0 - mà không cần cho thêm một module bên ngoài nào. Nhìn vào đoạn mã sau để đọc thẻ ID3v1 của một tập tin MP3:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct ID3v1Tag
{
 private fixed sbyte tag[3];
 private fixed sbyte title[30];
 ...
}
using (System.IO.BinaryFile fmp3 = new System.IO.BinaryFile("myfile.mp3", System.IO.FileMode.Open))
{
 ID3v1Tag t;

 unsafe
 {
  fmp3.Seek(-128, System.IO.SeekOrigin.End);
  fmp3.ReadStruct<ID3v1Tag>(&t);
 }
 if (t.Tag == "TAG")
 {
  Console.WriteLine("title: " + t.Title); ...
 }

}

Tôi muốn nói đó là dễ dàng để đọc / ghi trên C + + tương đương. Các dữ liệu ID3v1 tag được đọc trực tiếp vào struct ID3v1Tag thông qua phương thức Read ().
Làm thế nào là thực hiện điều này?
Tôi không sử dụng System.IO để truy cập các tập tin, nhưng sử dụng các hàm fxxx(). Lớp BinaryFile trên đóng gói các cuộc gọi đến các hàm C DLL sau:
[System.Runtime.InteropServices.DllImport("CRTFileIO.dll")]
private static extern int FileOpen(string filename, string mode);
[System.Runtime.InteropServices.DllImport("CRTFileIO.dll")]
private static extern void FileClose(int hStream);
[System.Runtime.InteropServices.DllImport("CRTFileIO.dll")]
private unsafe static extern bool FileReadBuffer(int hStream, void* buffer, short bufferLen);
[System.Runtime.InteropServices.DllImport("CRTFileIO.dll")]
private unsafe static extern bool FileWriteBuffer(int hStream, void* buffer, short bufferLen);
[System.Runtime.InteropServices.DllImport("CRTFileIO.dll")]
private unsafe static extern bool FileSeek(int hStream, int offset, short origin);
[System.Runtime.InteropServices.DllImport("CRTFileIO.dll")]
private unsafe static extern bool FileGetPos(int hStream, out int pos);
[System.Runtime.InteropServices.DllImport("CRTFileIO.dll")]
private unsafe static extern bool FileFlush(int hStream);
Tôi chỉ cần viết một wrapper DLL unmanaged xung quanh các chức năng cơ bản C stdio như fopen (), fread () ... Đó là tất cả sự kỳ diệu có. Nhìn vào chức năng C của tôi để đọc dữ liệu từ một tập tin:
extern "C" DLLEXPORT short __stdcall FileReadBuffer(FILE *stream, void *buffer, int bufferLen)
{
 int n = fread(buffer, 1, bufferLen, stream);
 return n == bufferLen;
}
Hàm này được gọi bởi phương thức của lớp đóng gói và làm cho chương trình làm việc với tập tin nhị phân dễ dàng hơn. BinaryFile dấu cac File HANDLE and nhìn giống như a FileStream (đó là lý do tại sao mình bỏ  BinaryFile vào System.IO namespace):
public unsafe bool ReadStruct<StructType>(void *buffer) where StructType : struct
{
  return Read(buffer, (short)System.Runtime.InteropServices.Marshal.SizeOf(typeof(StructType)));
}
public unsafe bool Read(void* buffer, short bufferLen)
{
 ...
 return FileReadBuffer(hFile, buffer, bufferLen);
}
Bạn chuyển địa chỉ của cấu trúc cho mà Read() để nhận dữ liệu từ File và số Byte đọc được. Hàm fread() sẽ bỏ dữ liệu vào struct của C#. không cần phải tách từng trường một. Bạn chỉ cần dùng đoạn mã unsafe sau:

unsafe
{
 fmp3.Read<MyStruct>(&myStructVar);
}
Tôi muốn nói, nó không thể trở nên dễ dàng hơn hoặc nhanh hơn này, khi đọc từ tập tin nhị phân.Nếu bạn muốn cung cấp cho phương pháp này một thử, bạn có thể download sources here.
Để dung BinaryFile class chỉ cần thêm reference  CRTFileIO.Import.dll vào  C# project và bảo đảm C wrapper CRTFileIO.dll chép cùng thư mục với CRTFileIO.Import.dll.
Enjoy!

Resources

[1] Anthony Baraff: Fast Binary File Reading with C#, http://www.codeproject.com/csharp/fastbinaryfileinput.asp
[2] Robert L. Bogue: Read binary files more efficiently using C#,http://www.builderau.com.au/architect/webservices/0,39024590,20277904,00.htm
[3] Eric Gunnerson: Unsafe and reading from files, http://blogs.msdn.com/ericgu/archive/2004/04/13/112297.aspx

Comments

# re: Easy high speed reading/writing of structured binary files using C#

Sunday, March 05, 2006 4:28 AM by Ayende Rahien
Assuming this is C# 2.0, and you need to do this on more than one struct, you can make it easier by using generics:

public T ReadStruct(string filename)<T> where T:struct, new()
using (System.IO.BinaryFile fmp3 = new System.IO.BinaryFile(filename, System.IO.FileMode.Open))
{
T t = new T()

unsafe
{
fmp3.Seek(-128, System.IO.SeekOrigin.End);
fmp3.Read(&t, (short)Marshal.SizeOf(typeof(T)));
}
return T;
}

# re: Easy high speed reading/writing of structured binary files using C#

Sunday, March 05, 2006 5:39 AM by Ralf
@Ayende: Thx for your idea. However, it introduces the very data copy I wanted to avoid: ReadStruct() returns a struct on the stack which probably needs to be copied to the real destination in the caller´s method.

Nonetheless using Generics could make my Read() method a little easier, since the struct length could be determined automatically.

-Ralf

# re: Easy high speed reading/writing of structured binary files using C#

Monday, February 19, 2007 10:29 AM by Daniele Bertocchi
       IntPtr ptr = IntPtr.Zero;
       Marshal.StructureToPtr(YourStruct, true);
       fs = new FileStream(Filename,FileMode.CreateNew,FileAccess.Write);        
       byte* bytedata = (byte*)ptr.ToPointer();
       for (int i = 0; i < Marshal.SizeOf(YourStruct); ++i)
       {
         fs.WriteByte(bytedata[i]);
       }

# re: Easy high speed reading/writing of structured binary files using C#

Friday, July 06, 2007 5:04 PM by Cesar Wilson
If you want to save an struct in C# like in C++
you must use MarshalAs attribute.
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct Empleado
{
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=32)]
public string name;
public UInt32 id;
}
With the MarshalAs attribute, you set that when you use the string in an unmanaged context, it would be used like an ANSI null terminated string of 32 bytes of fixed size.
you can use the string member of the struct like a normal string. When you wanto to write the struct into a binary file, you must use a code like this:
Empleado emp = new Empleado();
FileStream fstream = new FileStream("C:\\binario.bin", FileMode.Create, FileAccess.Write);
BinaryWriter binwriter = new BinaryWriter(fstream);
emp.name = "Estuardo";
emp.id = 0x00112233;
int size = Marshal.SizeOf(emp);
IntPtr handle = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(emp, handle, true);
byte* ptr = (byte*)handle.ToPointer();
while(size-- != 0)
{
   binwriter.Write(*ptr++);
}
Marshal.FreeHGlobal(handle);
binwriter.Close();
this code is only valid in an unsafe context
(you must compile your code with the /unsafe option). The Marshal class is declared in the
System.Runtime.Interop namespace

Đọc/ghi dữ liệu chứng khoán trong Metastock Files bằng C++


Phần mềm phân tích kĩ thuật Metastock của Reuters khá nổi tiếng. Tuy giao diện của Metastock không thể so sánh với các phần mềm phân tích kỹ thuật khác như AmiBroker,...nhưng với rất nhiều công cụ hữu ích Expert Advisors, Indicator Builder, Exhanced System Test, The Explorer, phần mềm đáp ứng khá đầy đủ yêu cầu của các Teachnical Analysis. Trong mục này, mình không trình bày cách viết các chỉ báo kĩ thuật sử dụng ngôn ngữ lập trình meta programming hay hướng dẫn sử dụng Metastock cơ bản. Bài viết hướng đến vấn đề giải quyết việc truy xuất dữ liệu của Metastock trong các Files (MASTER, EMASTER, XMASTER, xxx.DAT). Trên mạng, mình thấy có trang web http://www.trading-tools.com/index.htm cung cấp module cho phép truy cập dữ liệu dưới dạng SDK hỗ trợ nhiều ngôn ngữ lập trình từ Python, C++, C#, VB.NET....nhưng giá rất cao. Phiên bản dành cho Commercial buyers giá khoản 450 USD. Làm sao có thể truy cập dữ liệu mà không phải trả giá quá đắc???? Vấn đề này được trình bày bởi nhiều người. Tuy nhiên, mình thấy khá phức tạp và không được chi tiết lắm. Vì vậy, mình muốn trình bày một số bước giúp các anh chị nào muốn truy xuất dữ liệu của Metastock với một vài bước đơn giản.

1) Metastock sử dụng kiểu dữ liệu Float để lưu trữ các thông tin (DATE, OPEN, CLOSE, HIGH, LOW,VOLOME) liên quan đến giá chứng khoán. Tuy nhiên, đây là kiểu dữ liệu cũ của Microsoft không thể dùng thể hiện khi ta truy xuất từ file của Metastock. Vấn đề chuyển đổi qua lại giữa chuẩn Microsoft và IEEE mình đã sao chép và upload trong blog trước.

2) Cấu trúc hệ thống FILE của METASTOCK như thế nào?????
- Metastock sử dụng FILE (MASTER,EMASTER, XMASTER) để chứa thông tin về các mã chứng khoán. Cơ bản thông tin đó bao gồm: Mã chứng khoán, thông tin, ngày bắt đầu, ngày kết thúc, và quan trong nhất là "Fx.DAT" trong đó "x" chỉ đến FILE.DAT chứa thông tin thực sự của mã chứng khoán đó.
- Các FILE.DAT có cấu trúc(DATE, OPEN, CLOSE, HIGH, LOW,VOLOME) lưu trữ dữ liệu của một mã chứng khoán nào đó. Để biết được đây thực sự là dữ liệu giao dịch của cổ phiếu nào, chúng ta cần so sánh thứ tự của File.DAT này với Record tương ứng trong MASTER FILE.

DƯỚI ĐÂY LÀ CẤU TRÚC DỮ LIỆU CHO CÁC FILE:
- Metastock.h: chứa cấu trúc dữ liệu của MASTER, EMASTER, XMASTER, FILEx.DAT

#if !defined( METASTOCK_H )
#define METASTOCK_H

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

// MetaStock.h : header file

#define MetaStockPack 1

// Remember the original packing (probably 8)
#pragma pack( push, OriginalPack, MetaStockPack )

#define METASTOCK_MASTER_FILE "MASTER.DAT"
#define METASTOCK_EMASTER_FILE "EMASTER.DAT"
#define CSI_MASTER_FILE "MASTER"

#define METASTOCK_DATA_FILE_TEMPLATE "F%i.dat"
#define METASTOCK_X_DATA_FILE_TEMPLATE "F%i.mwd"

#define LAST_MASTER_F_NUMBER 255
#define UINT unsigned int
#define USHORT unsigned short
#define CHAR char
#define UCHAR unsigned char
#define FLOAT float
#define INT int

//--------------------------------------------------------------
// MASTER file description (the original 255 record format:
// floats are in Microsoft Basic format
// strings are padded with spaces, not null terminated
//--------------------------------------------------------------
struct MasterHeader {
    USHORT totalFiles; // Number of files master contains
    USHORT lastFNumber; // Next file number to use (highest F# used)
    CHAR padding[45];
};

typedef struct MasterRecord {  
    UCHAR fileFNumber; // File #, i.e., F#
    CHAR fileType[2]; // CT file type = 0'e' (5 or 7 flds)
    UCHAR recordLength; // Record length in bytes (4 x num_fields)
    UCHAR totalFields; // Number of 4-byte fields in each record
    CHAR padding1[2];
    CHAR description[16]; // Stock or futures market name
    CHAR        descriptionEnd; //
    CHAR version28; // If CT ver. 2.8, 'Y'; o.w., anything else
    FLOAT firstDate; // yymmdd
    FLOAT lastDate; //
    CHAR period; // Data format: 'I'(IDA)/'W'/'Q'/'D'/'M'/'Y'
    USHORT intraDayTimeBase; // intraday (IDA) time base
    CHAR symbol[14]; // Stock symbol
    CHAR symbolEnd; // MetaStock reserved2: must be a space
    CHAR flag; // ' ' or '*' for autorun
    CHAR padding4; //
} MasterRecord, *MasterRecordPtr;

typedef struct MasterFile {

MasterHeader header;
MasterRecord records[4];

} MasterFile, *MasterFilePtr;
//--------------------------------------------------------------
// EMASTER file description:
// floats are in IEEE format
// strings are padded with nulls
//--------------------------------------------------------------

struct EMasterHeader {
    USHORT totalFiles; // number of files in emaster */
    USHORT file_num; // last (highest) file number */
    CHAR stuff[188];
};

typedef struct EMasterRecord {
    CHAR asc30[2];    // "30";
    UCHAR fileFNumber; // File number F#
    CHAR fill1[3];
    UCHAR totalFields; // number of 4-byte data fields
    CHAR fill2[2];
    CHAR flag; // ' ' or '*' for autorun
    CHAR fill3;
    CHAR symbol[13]; // Stock symbol
    CHAR symbolEnd; // Stock symbol
    CHAR fill4[7];
    CHAR description[15];// Stock or futures name
    CHAR descriptionEnd; // End
    CHAR fill5[12];
    CHAR period; // Data format: 'D','W', 'M', etc.
    CHAR fill6[3];
    FLOAT firstDate;    // Date - YYMMDD
    CHAR fill7[4];
    FLOAT lastDate; // Date - YYMMDD
    CHAR fill8[116];
} EMasterRecord, *EMasterRecordPtr;

typedef struct EMasterFile {

EMasterHeader header;
EMasterRecord records[4];

} EMasterFile, *EMasterFilePtr;
//--------------------------------------------------------------
// XMASTER file description (150 byte records):
// no floats
// strings are padded with nulls
//--------------------------------------------------------------

struct XMasterHeader {
// OFS - Decimal Offset
CHAR char5D; // 000 - 0x5D
CHAR charFE; // 001 - 0xFE
CHAR xmChars[2]; // 002 - "XM"
CHAR pad[6];
USHORT totalFiles; // 010 - Number of files master contains
CHAR pad2[2];
USHORT totalFiles2; // 014 - Number of files master contains
CHAR pad3[2];
USHORT lastFNumber; // 018 - Next file number to use (highest F# used)
CHAR padding[130];
};

typedef struct XMasterRecord {
CHAR onePad; // 000 - 0x01
CHAR symbol[15]; // 001 - ASCII Symbol (zero terminated)
CHAR description[32]; // 016 - ASCII Description
CHAR pad[14];
CHAR period; // 062 - Data period: 'D','W', 'M', etc.
CHAR pad2[2];
USHORT fileFNumber; // 065 - File number F#
CHAR pad3[13];
INT firstDate; // 080 - First Data Date
CHAR pad4[20];
INT lastDate; // 104 - Last Data Date
INT firstTradingDate; // 108 - Start of Trading for Instrument?
INT lastDate2; // 112 - Start Date?
CHAR pad5[34];
} XMasterRecord, *XMasterRecordPtr;

typedef struct XMasterFile {

XMasterHeader header;
XMasterRecord records[4];

} XMasterFile, *XMasterFilePtr;

//-----------------------------------------------------------------
// Seven-field Data File Description


// Data Header
//-----------------------------------------------------------------
struct MetaStockDataHeader {
    USHORT dontUse_TotalRecords;
                                    // The number of records. NOTE: This is not filled in by CSI so don't use.
    USHORT lastRecord;  
                                   // The last record in the file, NOTE: The header is one, the records start at two.
    CHAR padding[24]; // Pad to get 28 bytes
};

// Data Record
typedef struct MetaStockRecord {
     CHAR         date[4]; // NOTE: Add these floats are in the bogus old MS Basic format.
    CHAR open[4]; // cac phan tu nay o dinh dang FLoat nhung theo chuan Microsoft
    CHAR high[4]; // do do de co the su dung duoc can chuyen sang dinh dang IEEE Float
    CHAR low[4];
    CHAR close[4];
    CHAR volume[4];
    CHAR openInterest[4];
} MetaStockRecord, *MetaStockRecordPtr;

typedef struct MetaStockDataFile {

MetaStockDataHeader header;
MetaStockRecord records[4];

} MetaStockDataFile, *MetaStockFilePtr;

// Restore the original packing
#pragma pack( pop, OriginalPack )
#endif // !defined( METASTOCK_H )


HÀM CHUYỂN ĐỔI TỪ ĐỊNH DẠNG FLOAT CỦA MICROSOFT SANG ĐỊNH DẠNG IEEE
float ConvertMBFToFloat(char* bytArray)
{
unsigned int *temp; // point to merory containing value
unsigned int valtemp;
// tranform CHAR ARRAY to UNSIGNED INT
temp = (unsigned int*) bytArray;
valtemp = *temp; // copy this value to valtemp
//Do shift some bits to change MBF to IEEE Float format
valtemp = (((valtemp - 0x02000000) & 0xFF000000) >> 1) |
        ((valtemp & 0x00800000) << 8) |
        (valtemp & 0x007FFFFF);

// tranform UNSIGNED INT to FLOAT
float* fresult = (float*)&valtemp;
return *fresult;
}
ĐỌC EMASTER FILE VÀ XUẤT THÔNG TIN MÃ CHỨNG KHOÁN/ NGÀY BẮT ĐẦU/ NGÀY KẾT THÚC:
void main ()
{
char          s_Buffer[BUFFER_SIZE];
FILE*                               masterFile;
EMasterFilePtr               masterPtr;

EMasterRecordPtr         masterRecordPtr;
int                                     fileIndex;


if( fopen_s( &masterFile, "EMASTER", "r" ) == 0 )

{
      // Attempt to read in 25 characters 
      numread = fread( s_Buffer, sizeof( char ),  BUFFER_SIZE , masterFile );
      printf( "Number of items read = %d\n", numread );
      printf( "Contents of buffer = %.25s\n",s_Buffer );
      fclose(masterFile);

}


// Get a pointer in the correct format.
masterPtr = (EMasterFilePtr) s_Buffer ;

for ( fileIndex = 0; fileIndex < masterPtr->header.totalFiles; fileIndex ++ )
{
// Get a pointer to the record.
masterRecordPtr = &masterPtr->records[ fileIndex ];
       
        //-------------------------------------------------------------------------
        // do what information you need at this point
        //-------------------------------------------------------------------------
        printf( "Stock code = %s\n", masterRecordPtr->symbol );
        printf( "First date = %.f\n", masterRecordPtr->firstdate);
        printf( "Last date = %.f\n", masterRecordPtr->lastdate);
}
}

ĐỌC Fxx.DAT  FILE VÀ XUẤT THÔNG TIN GIAO DICH CHỨNG KHOÁN:


void main ()
{
char          s_Buffer[BUFFER_SIZE];
FILE* stockFile;

MetaStockFilePtr metaStockFilePtr;
MetaStockRecordPtr metaRecordPtr;

int                                     fileIndex;



//Read Stock Data in F1.Dat
if( fopen_s(&stockFile, "F1.DAT", "r" ) == 0 )
{
       // Attempt to read in 25 characters 
      numread = fread( s_Buffer, sizeof( char ),
BUFFER_SIZE

, stockFile );
      printf( "Number of items read = %d\n", numread );
      printf( "Contents of buffer = %.25s\n",s_Buffer );
      fclose(stockFile);
}

// Get a pointer in the correct format.
 metaStockFilePtr = (MetaStockFilePtr) s_Buffer;

for ( fileIndex = 0; fileIndex < metaStockFilePtr->header.lastRecord; fileIndex ++ )
{
// Get a pointer to the record.
metaRecordPtr = &metaStockFilePtr->records[ fileIndex ];


        //-------------------------------------------------------------------------
        // do what information you need at this point
        //-------------------------------------------------------------------------
        float open, close, high, low, date;
        open  = ConvertMBFToFloat(metaRecordPtr->open);
        high = ConvertMBFToFloat(metaRecordPtr->high);
        close = ConvertMBFToFloat(metaRecordPtr->close);
        low =ConvertMBFToFloat(metaRecordPtr->low);
        date = ConvertMBFToFloat(metaRecordPtr->date);
        printf( "Date: %f  with OPEN: %f, HIGH: %f, LOW: %f, CLOSE: %f", day, open, high,      low, close);
}
}

Thứ Tư, 30 tháng 5, 2012

Chuyển đổi từ Microsoft Binary Format (single precision) thành IEEE 754 Single format

Here's the format of the two data types.



IEEE 754 Single format
======================
32 bits long (4 bytes)

sign (1 bit)| exponent (8 bits) | fraction (23 bits)

The exponent is biased by 127. 
There is an assumed 1 bit before the radix point 
 (so the assumed mantissa is 1.ffff... where f's are the fraction bits)


Microsoft Binary Format (single precision)
=======================           
32 bits long (4 bytes)

exponent (8 bits) | sign (1 bit) | fraction (23 bits)

The exponent is biased by 128. 
There is an assumed 1 bit after the radix point 
  (so the assumed mantissa is 0.1ffff... where f's are the fraction bits)


   public static float ConvertMbf4ToFloat(byte[] mbf) {
      if ((mbf == null) || (mbf.Length != 4))
        throw new ArgumentException("Invalid MBF array");

      if (mbf[3] == 0) return 0.0f;
      if (mbf[3] <= 2)
        throw new ArgumentException(
          "Underflow when converting from MBF to single");

      UInt32 temp = BitConverter.ToUInt32(mbf, 0);
      temp = (((temp - 0x02000000) & 0xFF000000) >> 1) |
        ((temp & 0x00800000) << 8) |
        (temp & 0x007FFFFF);
      byte[] single = BitConverter.GetBytes(temp);
      return BitConverter.ToSingle(single, 0);
    }
    public static byte[] ConvertFloatToMbf4(float s) {
      if (s == 0.0f) {
        return new byte[4];
      }

      if (Single.IsNaN(s))
        throw new ArgumentException(
          "Cannot convert a NaN to MBF format");
      if (Single.IsInfinity(s))
        throw new ArgumentException(
          "Cannot convert an infinity to MBF format");

      byte[] single = BitConverter.GetBytes(s);
      UInt32 temp = BitConverter.ToUInt32(single, 0);
      temp = (((temp & 0x7F800000) << 1) + 0x02000000) |
        ((temp & 0x80000000) >> 8) |
        (temp & 0x007FFFFF);

      return BitConverter.GetBytes(temp);
    }
  
static void Main(string[] args)
{
            byte[] byte_b = new byte[4];
            float float_a = 100.34f;
            float float_c;

            byte_b = ConvertFloatToMbf4(float_a);
            float_c = ConvertMbf4ToFloat(byte_b);

            Console.Write("Float: {0}", float_a);
            Console.WriteLine();
            Console.Write("Byte Array {0},{1},{2},{3}", byte_b[0], byte_b[1], byte_b[2], byte_b[3]);
            Console.WriteLine();
            Console.Write("Float is re-changed: {0}", float_c);
            Console.WriteLine();
 }

Thứ Hai, 28 tháng 5, 2012

String Format for Double [C#]


The following examples show how to format float numbers to string in C#. You can use static method String.Format or instance methods double.ToString and float.ToString.

Digits after decimal point

This example formats double to string with fixed number of decimal places. For two decimal places use pattern „0.00“. If a float number has less decimal places, the rest digits on the right will be zeroes. If it has more decimal places, the number will be rounded.
[C#]
// just two decimal places
String.Format("{0:0.00}", 123.4567);      // "123.46"
String.Format("{0:0.00}", 123.4);         // "123.40"
String.Format("{0:0.00}", 123.0);         // "123.00"

Next example formats double to string with floating number of decimal places. E.g. for maximal two decimal places use pattern „0.##“.
[C#]
// max. two decimal places
String.Format("{0:0.##}", 123.4567);      // "123.46"
String.Format("{0:0.##}", 123.4);         // "123.4"
String.Format("{0:0.##}", 123.0);         // "123"

Digits before decimal point

If you want a float number to have any minimal number of digits before decimal point use N-times zero before decimal point. E.g. pattern „00.0“ formats a float number to string with at least two digits before decimal point and one digit after that.
[C#]
// at least two digits before decimal point
String.Format("{0:00.0}", 123.4567);      // "123.5"
String.Format("{0:00.0}", 23.4567);       // "23.5"
String.Format("{0:00.0}", 3.4567);        // "03.5"
String.Format("{0:00.0}", -3.4567);       // "-03.5"

Thousands separator

To format double to string with use of thousands separator use zero and comma separator before an usual float formatting pattern, e.g. pattern „0,0.0“ formats the number to use thousands separators and to have one decimal place.
[C#]
String.Format("{0:0,0.0}", 12345.67);     // "12,345.7"
String.Format("{0:0,0}", 12345.67);       // "12,346"

Zero

Float numbers between zero and one can be formatted in two ways, with or without leading zero before decimal point. To format number without a leading zero use # before point. For example „#.0“ formats number to have one decimal place and zero to N digits before decimal point (e.g. „.5“ or „123.5“).
Following code shows how can be formatted a zero (of double type).
[C#]
String.Format("{0:0.0}", 0.0);            // "0.0"
String.Format("{0:0.#}", 0.0);            // "0"
String.Format("{0:#.0}", 0.0);            // ".0"
String.Format("{0:#.#}", 0.0);            // ""

Align numbers with spaces

To align float number to the right use comma „,“ option before the colon. Type comma followed by a number of spaces, e.g. „0,10:0.0“ (this can be used only in String.Format method, not indouble.ToString method). To align numbers to the left use negative number of spaces.
[C#]
String.Format("{0,10:0.0}", 123.4567);    // "     123.5"
String.Format("{0,-10:0.0}", 123.4567);   // "123.5     "
String.Format("{0,10:0.0}", -123.4567);   // "    -123.5"
String.Format("{0,-10:0.0}", -123.4567);  // "-123.5    "

Custom formatting for negative numbers and zero

If you need to use custom format for negative float numbers or zero, use semicolon separator;“ to split pattern to three sections. The first section formats positive numbers, the second section formats negative numbers and the third section formats zero. If you omit the last section, zero will be formatted using the first section.
[C#]
String.Format("{0:0.00;minus 0.00;zero}", 123.4567);   // "123.46"
String.Format("{0:0.00;minus 0.00;zero}", -123.4567);  // "minus 123.46"
String.Format("{0:0.00;minus 0.00;zero}", 0.0);        // "zero"

Some funny examples

As you could notice in the previous example, you can put any text into formatting pattern, e.g. before an usual pattern „my text 0.0“. You can even put any text between the zeroes, e.g. „0aaa.bbb0“.
[C#]
String.Format("{0:my number is 0.0}", 12.3);   // "my number is 12.3"
String.Format("{0:0aaa.bbb0}", 12.3);          // "12aaa.bbb3"