【问题标题】:Marshal C++ float to C# float accuracy problemMarshal C++ float to C# float 精度问题
【发布时间】:2011-02-23 18:16:50
【问题描述】:

我有一个 DBase IV 数据库。每行都有一个带有 ASCII 编码字符串的备注字段,该字符串包含两个序列化的 borland c++ 结构。我可以使用 OleDb 提取数据,使用 ASCIIEncoding 类将其重新编码为 ascii,使用 BinaryReader 将其转换为字节,然后使用 Marshal.PtrToStructure 将其转换为我的 C# 结构。我得到的数据是正确的,但是当它被转换到 c# 时,数据库中任何大的浮点数都是完全错误的。例如,将 1149.00 的值转换为 764.9844,但将 64.00 之类的值转换为精细。我可以发布一些代码和结构,但我想我一开始会尽量保持简短。我知道浮点数最多只能精确到 7 位,但我很困惑为什么我会看到这个,因为值低于该限制。

编辑:

struct cplusplusstruct // from the c++ code
{
  int   Number;
  float P;
  float ZP;
  float Hours;
  int   Month;
  int   Day;
  int   Year;
  int   Hour;
  int   Minute;
  int   Second;
  ULONG UPCTime;
  int   B;
  char  Name[21];
  float L;
  float H;
  float S;
}


[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct csharpstruct  //The C# struct I created
{
     public int Number;
     public float Pr;
     public float ZP;
     public float Hours;
     public int Month;
     public int Day;
     public int Year;
     public int Hour;
     public int Minute;
     public int Second;
     public UInt32 UPCTime;
     public int B;
 [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 21)]
     public string Name;
     public float L;
     public float H;
     public float S;
 }


//OLE DB Connection and query ...

//Casting data to struct
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] blob = encoding.GetBytes(memoString);
MemoryStream memoryStream = new MemoryStream(blob);
BinaryReader binaryReader = new BinaryReader(memoryStream);

int dataSize = Marshal.SizeOf(typeof(csharpstruct));
GCHandle handle = GCHandle.Alloc(binaryReader.ReadBytes(dataSize), GCHandleType.Pinned);
csharpstruct data = (csharpstruct) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(csharpstruct));

编辑:以下是 java 代码,可以很好地读取数据,但没有使用任何强制转换。

org.xBaseJ.DBF dbf = new org.xBaseJ.DBF(dbPath);
org.xBaseJ.DBF dbf = new org.xBaseJ.DBF(dbPath);
MemoField m = (MemoField) dbf.getField("MEMOFIELD");

Charset charset = Charset.forName("US-ASCII");
CharsetDecoder decoder = charset.newDecoder();
ByteBuffer trendBytes = ByteBuffer.wrap(m.getBytes());
trendBytes.order(ByteOrder.LITTLE_ENDIAN);
trendBytes.getInt();
trendBytes.getFloat();

【问题讨论】:

  • 想发布一些代码 sn-ps 吗?
  • C++ 结构是双精度还是编译为使用不同的浮点模型?
  • @Sparkie - 如果有帮助我会的
  • @plinth - c++ 结构中的数据类型是浮点数。我不确定浮点模型,但它是使用旧版本的 Borland C++ 编译器编译的。
  • 数据以ascii形式保存到数据库中。如果不重新编码为 ascii,我会得到一堆乱码。

标签: c# c++ floating-point dbase


【解决方案1】:

您的 C# 结构中有 Pack = 1,但尚未说明您的 C++ 结构是否已打包。由于您的浮点数(21 个字符的字符串)之前有一个奇数大小的字段,这可能会导致麻烦并意味着您的浮点数被读取时未对齐。之前的所有内容都有 4 个字节长,因此打包不太可能给您带来问题。在继续之前,我会确保包装在 C# 和 C++ 中都匹配。

【讨论】:

  • C++ 标头指定#pragma pack(1)。
  • 另请注意,此问题发生在结构中的所有浮点数上。如果值在 1000 以内,它就会变得混乱。如果不是,那么我得到正确的数据。
【解决方案2】:

我无法直接解决问题。问题似乎来自我正在使用的 OLE 数据提供程序。从数据库中检索的数据与xBaseJ 提供的数据略有不同。我最终使用 IKVM.NET 将 xBaseJ 转换为 CLI 字节码。这允许我用 xBaseJ 阅读器替换 OLE 数据提供程序。我的其余代码保持不变。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2018-11-29
    • 1970-01-01
    • 2012-07-18
    • 2011-03-30
    • 1970-01-01
    相关资源
    最近更新 更多