- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
梦想
我正在寻找一种将十进制值复制到字节数组缓冲区中的方法,然后能够在没有任何堆分配的情况下将这些字节读回十进制。理想情况下,这不需要不安全的上下文。
我的尝试
我以前在 C# 中使用临时联合来做一些疯狂的事情。这是一种以您想要的任何随机方式读取内存的非常酷的方式,但您必须小心。你可以进入一个变量明确存在的损坏状态,例如 byte[]
但在调试器中查看的值是 int[]
.我什至不知道这样的事情是可能的!
注意:Marc 在下面的评论中提出了一个非常重要的观点。由于字节顺序,您无法使用像这样的重叠结构概念可靠地将数字直接转换为字节。在这种情况下,您可以安全地使用整数,因为十进制类型在内部使用了 4 个整数。这是来自 protobuf-net 的十进制序列化程序的 [示例]。
1: struct union w/decimal 和 byte[]
第一次尝试尝试使用带有 decimal
的结构联合概念。和 byte[]
字段,都在 0 偏移处,因此它们占用完全相同的内存位置。然后我可以写入一个字段并从另一个字段读取。
[StructLayout(LayoutKind.Explicit)]
private readonly struct convert_decimal_to_bytes
{
[FieldOffset(0)]
public readonly decimal value;
[FieldOffset(0)]
public readonly byte[] bytes;
public convert_decimal_to_bytes(decimal value)
{
bytes = default;
this.value = value;
}
}
这甚至不会在没有抛出的情况下运行 - 类型无法加载以下内容:
System.TypeLoadException : Could not load type 'convert_decimal_to_bytes' from assembly 'teloneum, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field.
显然 CLR 不喜欢它们被重叠——但这只是因为一个是值类型而另一个是引用类型。
[StructLayout(LayoutKind.Explicit)]
private readonly struct convert_decimal_to_bytes
{
[FieldOffset(0)] public readonly decimal value;
[FieldOffset( 0)] public readonly byte byte_1;
[FieldOffset( 1)] public readonly byte byte_2;
[FieldOffset( 2)] public readonly byte byte_3;
[FieldOffset( 3)] public readonly byte byte_4;
[FieldOffset( 4)] public readonly byte byte_5;
[FieldOffset( 5)] public readonly byte byte_6;
[FieldOffset( 6)] public readonly byte byte_7;
[FieldOffset( 7)] public readonly byte byte_8;
[FieldOffset( 8)] public readonly byte byte_9;
[FieldOffset( 9)] public readonly byte byte_10;
[FieldOffset(10)] public readonly byte byte_11;
[FieldOffset(11)] public readonly byte byte_12;
[FieldOffset(12)] public readonly byte byte_13;
[FieldOffset(13)] public readonly byte byte_14;
[FieldOffset(14)] public readonly byte byte_15;
[FieldOffset(15)] public readonly byte byte_16;
public convert_decimal_to_bytes(decimal value)
{
byte_1 = default;
byte_2 = default;
byte_3 = default;
byte_4 = default;
byte_5 = default;
byte_6 = default;
byte_7 = default;
byte_8 = default;
byte_9 = default;
byte_10 = default;
byte_11 = default;
byte_12 = default;
byte_13 = default;
byte_14 = default;
byte_15 = default;
byte_16 = default;
this.value = value;
}
public convert_decimal_to_bytes(int startIndex, byte[] buffer)
{
value = default;
byte_1 = buffer[startIndex++];
byte_2 = buffer[startIndex++];
byte_3 = buffer[startIndex++];
byte_4 = buffer[startIndex++];
byte_5 = buffer[startIndex++];
byte_6 = buffer[startIndex++];
byte_7 = buffer[startIndex++];
byte_8 = buffer[startIndex++];
byte_9 = buffer[startIndex++];
byte_10 = buffer[startIndex++];
byte_11 = buffer[startIndex++];
byte_12 = buffer[startIndex++];
byte_13 = buffer[startIndex++];
byte_14 = buffer[startIndex++];
byte_15 = buffer[startIndex++];
byte_16 = buffer[startIndex];
}
public static void Copy(decimal value, int startIndex, byte[] buffer)
{
var convert = new convert_decimal_to_bytes(value);
buffer[startIndex++] = convert.byte_1;
buffer[startIndex++] = convert.byte_2;
buffer[startIndex++] = convert.byte_3;
buffer[startIndex++] = convert.byte_4;
buffer[startIndex++] = convert.byte_5;
buffer[startIndex++] = convert.byte_6;
buffer[startIndex++] = convert.byte_7;
buffer[startIndex++] = convert.byte_8;
buffer[startIndex++] = convert.byte_9;
buffer[startIndex++] = convert.byte_10;
buffer[startIndex++] = convert.byte_11;
buffer[startIndex++] = convert.byte_12;
buffer[startIndex++] = convert.byte_13;
buffer[startIndex++] = convert.byte_14;
buffer[startIndex++] = convert.byte_15;
buffer[startIndex] = convert.byte_16;
}
public static decimal Read(int startIndex, byte[] buffer)
{
var convert = new convert_decimal_to_bytes(startIndex, buffer);
return convert.value;
}
}
最佳答案
在 .NET 5.0 之前,如果没有一些丑陋的黑客,这很尴尬。从 .NET 5.0 开始,有更多方法接受跨度。
您可以使用 GetBits(decimal d, Span<int>)
使用堆栈分配范围的方法,然后根据需要将四个整数转换为现有的字节数组,例如与 BitConverter.TryWriteBytes
.
在另一个方向,有一个 Decimal(ReadOnlySpan<int>)
构造函数,所以你可以再次 stackalloc 一个 Span<int>
, 使用 BitConverter.ToInt32(ReadOnlySpan<byte>)
重复从字节数组填充该跨度,并将其传递给构造函数。
顺便说一句,您可能希望通过代码库更广泛地接受跨度,而不是接受字节数组和起始索引。
这是一些完成上述所有操作的示例代码 - 很可能可以稍微更有效地完成它,但希望这能传达这个想法,并且这确实避免了分配:
using System;
class Program
{
public static void Copy(decimal value, int startIndex, byte[] buffer)
{
Span<int> int32s = stackalloc int[4];
decimal.GetBits(value, int32s);
var bufferSpan = buffer.AsSpan();
for (int i = 0; i < 4; i++)
{
// These slices are bigger than we need, but this is the simplest approach.
var slice = bufferSpan.Slice(startIndex + i * 4);
if (!BitConverter.TryWriteBytes(slice, int32s[i]))
{
throw new ArgumentException("Not enough space in span");
}
}
}
public static decimal Read(int startIndex, byte[] buffer)
{
Span<int> int32s = stackalloc int[4];
ReadOnlySpan<byte> bufferSpan = buffer.AsSpan();
for (int i = 0; i < 4; i++)
{
var slice = bufferSpan.Slice(startIndex + i * 4);
int32s[i] = BitConverter.ToInt32(slice);
}
return new decimal(int32s);
}
static void Main()
{
byte[] bytes = new byte[16];
decimal original = 1234.567m;
Copy(original, 0, bytes);
decimal restored = Read(0, bytes);
Console.WriteLine(restored);
}
}
MemoryMarshal
做同样的事情:
public static void Copy(decimal value, int startIndex, byte[] buffer)
=> decimal.GetBits(value, MemoryMarshal.Cast<byte, int>(buffer.AsSpan(startIndex)));
public static decimal Read(int startIndex, byte[] buffer)
=> new decimal(MemoryMarshal.Cast<byte, int>(buffer.AsSpan(startIndex)));
关于c# - 将十进制复制到字节数组而不分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64906392/
我正在尝试编写一个程序,该程序接受十六进制、八进制和小数的输入,将它们存储在整数变量中,并将它们连同它们转换为十进制形式一起输出。例如: 用户输入:0x43、0123、65 程序输出: 0x43 he
var re = /^([0-9]*)(\.[0-9]{2})$/ re.test(.22) true re.test(.20) false re.test(10.02) true re.test(1
我有一个类型为BigDecimal的属性“initialPrice”的“Trade”类。该属性可以 根据另一个类别“Symbol”中包含的属性“decimals”,小数位数会有所不同,因此需要使用不同
我是这里编码的新手。 我正在尝试使用编码来显示平均值、最大值和最小值的统计信息。 我遇到了错误,他们说我无法将 decimal[] 转换为 int[]。我在我的代码旁边评论了下面的错误。这是最后几行之
在不久的将来,我一直在研究小数类型以获得一些可能的编程乐趣,并希望将它用作比 Int64 更大的整数。一个关键点是我需要找出我可以安全地存储为小数(不丢失精度)的最大整数;我这样说,因为显然它在那里使
所以我这样做了: for(i=1;i0;i--) { if(MASKBINARY[i-1]==1 && MASKBINARY[i]==0) // check if the next eleme
我正在尝试将数字四舍五入到最接近的指定小数。 我希望它四舍五入到小数点 .11、.22、.33、.44、.55、.66、.77、.88 但不是 .99。相反,0.99 应该是 1。 例如: 1.14
获取 python (python 3) Decimal 的整数部分和小数部分的最有效方法是什么? 这是我现在拥有的: from decimal import * >>> divmod(Decimal
我有一个使用十进制列表样式的 ol: ol li { list-style-type: decimal; } First Second 编号工作正常,但如何删除句点?而不是显示: 1.
将字节数组转换为具有所选基数的字符串的最佳方法是什么? S.O. 上有大量示例。和其他地方转换为十六进制字符串。我在这里主要感兴趣的是将十六进制或十进制字符串转换为其他;也是一种更通用的方式。 这是我
不清楚十进制类型的 sizeof。以字节为单位的大小是否像在 sql server 中一样因精度而异? c# 类型的精度变量是“十进制”吗? 我不想打开不安全的代码来只调用小数类型的 sizeof。你
我必须向十进制值添加尾随零。不仅用于显示(因此 Format 不是一个选项),而且用于实际的底层数据,因为小数精度在我们的应用程序中很重要。 我试过: decimal value = 1M decim
我正在使用以下代码行将 decimal 转换为 string: decimal a = 0; a.ToString(); Resharper 给了我以下警告:“明确指定字符串区域性”。我想这是有道理的
我注意到 .NET 在涉及小数和尾随零时有一些古怪/不直观的行为。 0m == 0.000m //true 0.1m == 0.1000m //true 但是 (0m).ToString() == (
最近写单片机 RTC 日期、时间配置,需要实现十进制、BCD码互换,将示例Demo分享给各位朋友: BCD是指用二进制来表示十进制数的编码,即:用4位二进制来表示一位十进制数,因此4位二进制数
这似乎是重复的,但我找不到合适的答案(问题足够接近但是..)我有一个代表十进制数的字符串,它总是有很多小数位,至少 20,有时最多 2000 (代表特定的验证计算,即像'是数字 135 到 147 素
我想知道我是否会收到这样的问题: "Convert a decimal number to two's complement, then give your answer in Hex". 下面是路径
此存储过程不返回十进制格式 00.00 的薪水 ALTER PROCEDURE taxable_varsalary @emp_code bigint, @co_id bigint AS de
使用 leaflet R 包,有没有办法将 zoom 设置为非整数(即十进制)值? 也就是说,介于这两个缩放级别之间: 例子 随着 zoom 从第 3 级移动到第 4 级,它看起来好像正在四舍五入到最
我如何编写一个函数来将十进制数字符串转换为十进制数并将十进制数转换为字符串? 最佳答案 有非常方便的 clojure 函数可以将任何内容转换为字符串以及将类似数字的内容转换为 BigDecimal:
我是一名优秀的程序员,十分优秀!