RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1583194
Accepted
Тихирун Ррр
Тихирун Ррр
Asked:2024-06-08 18:38:14 +0000 UTC2024-06-08 18:38:14 +0000 UTC 2024-06-08 18:38:14 +0000 UTC

在 C# 中将小数转换为另一个数字系统中的字符串

  • 772

有两个 ulong 数字 - 一个整数和一个小数部分,二进制形式看起来像 $"{IntegerPart.ToString("B")}.{FractionalPart.ToString("B")}",即小数部分是实际小数部分乘以 2^64。任务是在某种数字系统中显示近似的小数。以下是整个号码的代码。图片中有测试。

global using ExFixP = StandartPhysics.Math.ExtraFixedPoint;

using System.Numerics;

namespace StandartPhysics.Math
{
    public struct ExtraFixedPoint
    {
        private readonly ulong IntegerPart;
        private readonly ulong FractionalPart;

        public readonly byte[] GetBytes()
        {
            return [.. new BigInteger(FractionalPart).ToByteArray(true).Concat(new BigInteger(IntegerPart).ToByteArray(true))];
        }
        #region ExtraFixedPoint
        public ExtraFixedPoint()
        {

        }
        internal ExtraFixedPoint(byte @int, byte frac)
        {
            IntegerPart = @int;
            FractionalPart = (ulong)(new BigInteger(frac) << 56);
        }
        internal ExtraFixedPoint(ushort @int, ushort frac)
        {
            IntegerPart = @int;
            FractionalPart = (ulong)(new BigInteger(frac) << 48);
        }
        internal ExtraFixedPoint(uint @int, uint frac)
        {
            IntegerPart = @int;
            FractionalPart = (ulong)(new BigInteger(frac) << 32);
        }
        internal ExtraFixedPoint(ulong @int, ulong frac)
        {
            IntegerPart = @int;
            FractionalPart = frac;
        }
        internal ExtraFixedPoint(Span<byte> @int, Span<byte> frac)
        {
            IntegerPart = (ulong)new BigInteger(@int, true);
            FractionalPart = (ulong)new BigInteger(frac, true);
        }
        public ExtraFixedPoint(string text, int @base = 10)
        {
            string[] array = text.Split(new char[] { ',', '.' }, 2, StringSplitOptions.TrimEntries);
            if (array.Length == 0) throw new ArgumentException("Wrong text value");

            foreach (char digit in array[0].Replace(".", "").Replace(",", ""))
            {
                IntegerPart = IntegerPart * (ulong)@base + GetValueFromChar(digit);
            }
            if (array.Length == 2)
            {
                BigInteger baseMultiplier = new BigInteger(1) << 64;
                for (int i = 0; i < array[1].Length; i++)
                {
                    int digit = Convert.ToInt32(array[1][i].ToString(), @base);
                    baseMultiplier /= (ulong)@base;
                    FractionalPart += (ulong)((digit * baseMultiplier) & ulong.MaxValue);
                }
            }
        }
        private static ulong GetValueFromChar(char val)
        {
            val = char.ToLower(val);
            return val switch
            {
                '0' => 0,
                '1' => 1,
                '2' => 2,
                '3' => 3,
                '4' => 4,
                '5' => 5,
                '6' => 6,
                '7' => 7,
                '8' => 8,
                '9' => 9,
                'a' => 10,
                'b' => 11,
                'c' => 12,
                'd' => 13,
                'e' => 14,
                'f' => 15,
                'g' => 16,
                'h' => 17,
                'i' => 18,
                'j' => 19,
                'k' => 20,
                'l' => 21,
                'm' => 22,
                'n' => 23,
                'o' => 24,
                'p' => 25,
                'q' => 26,
                'r' => 27,
                's' => 28,
                't' => 29,
                'u' => 30,
                'v' => 31,
                'w' => 32,
                'x' => 33,
                'y' => 34,
                'z' => 35,
                _ => 0
            };
        }
        #endregion
        #region operators
        public static ExFixP operator +(ExFixP a, ExFixP b)
        {
            BigInteger bigInteger = new BigInteger(a.GetBytes(), true) + new BigInteger(b.GetBytes(), true);
            ulong fractional = (ulong)(bigInteger & ulong.MaxValue);
            bigInteger >>= 8;
            ulong integer = (ulong)(bigInteger & ulong.MaxValue);

            return new ExFixP(integer, fractional);
        }
        public static ExFixP operator -(ExFixP a, ExFixP b)
        {
            BigInteger bigInteger = new BigInteger(a.GetBytes(), true) - new BigInteger(b.GetBytes(), true);
            ulong fractional = (ulong)(bigInteger & ulong.MaxValue);
            bigInteger >>= 8;
            ulong integer = (ulong)(bigInteger & ulong.MaxValue);

            return new ExFixP(integer, fractional);
        }
        public static ExFixP operator *(ExFixP a, ExFixP b)
        {
            BigInteger bigInteger = new BigInteger(a.GetBytes(), true) * new BigInteger(b.GetBytes(), true);
            bigInteger >>= 8;
            ulong fractional = (ulong)(bigInteger & ulong.MaxValue);
            bigInteger >>= 8;
            ulong integer = (ulong)(bigInteger & ulong.MaxValue);

            return new ExFixP(integer, fractional);
        }
        //public static exfixp operator /(exfixp a, exfixp b)
        //public static exfixp operator %(exfixp a, exfixp b)
        //public static exfixp operator -(exfixp a)
        //public static exfixp operator +(exfixp a)
        //public static exfixp operator >>(exfixp a, int b)
        //public static exfixp operator <<(exfixp a, int b)
        //public static exfixp operator ++(exfixp a)
        //public static exfixp operator --(exfixp a)
        #endregion
        #region other
        public readonly override string ToString()
        {
            return ToString();
        }
        public readonly string ToDebugString()
        {
            return $"{IntegerPart:B}.{FractionalPart.ToString("B").PadLeft(64, '0')}";
        }
        public readonly string ToString(int Base = 10, int accuracy = 30)
        {
            Base = int.Clamp(Base, 2, 36);
            string integerPartBaseN = ConvertToBaseN(IntegerPart, Base);
            string fractionalPartBaseN = ConvertFractionalPartToBaseN(FractionalPart, Base, accuracy);

            return $"{integerPartBaseN}.{fractionalPartBaseN}";
        }

        private static string ConvertToBaseN(ulong number, int n)
        {
            if (number == 0) return "0";

            string result = "";
            while (number > 0)
            {
                ulong remainder = number % (ulong)n;
                result = GetCharFromNumber(remainder) + result;
                number /= (ulong)n;
            }

            return result;
        }

        private static string ConvertFractionalPartToBaseN(ulong fractionalPart, int n, int accuracy)
        {
            accuracy = int.Clamp(accuracy, 2, 40);
            string result = "";
            const ulong denominator = 1UL << 64; // 2^64

            for (int i = 0; i < accuracy; i++)  // ограничим вывод accuracy разрядами для дробной части
            {
                fractionalPart *= (ulong)n;
                ulong digit = fractionalPart / denominator;
                result += GetCharFromNumber(digit);
                fractionalPart %= denominator;
            }
            return result.TrimEnd('0').PadRight(1, '0'); // удалим нули в конце
        }

        private static char GetCharFromNumber(ulong number)
        {
            if (number < 10)
                return (char)('0' + number);
            else
                return (char)('A' + (number - 10));
        }
        #endregion
    }
}

计划结果

值得尝试解释为什么我需要这个。我最近(很久以前)研究了 IEEE754 标准的操作原理,并尝试重现其操作原理,但针对的是 128 位数字。但在实现它之前,我决定首先尝试实现定点数,然后再转向浮点数。构造函数和 ToString 中的 Base 指示在哪个数字系统中输入或输出数字,以十六进制(我最喜欢)、十进制(标准)或任何其他(尽管大约)输出。

c#
  • 2 2 个回答
  • 51 Views

2 个回答

  • Voted
  1. aepot
    2024-06-09T03:03:29Z2024-06-09T03:03:29Z

    由于问题是算法问题,所以我不会编写任何代码。我只会指出错误。

    有一个描述IEEE-754浮点数的标准。他告诉我们,带点的数字包含两个部分:尾数和度数。尾数是数字的重要部分,度数是您需要提高数字系统的基数以将尾数乘以结果并获得该数字系统中数字的表示形式。

    例如,要获得1.25十进制系统,您需要一个尾数125和一个指数(幂)-2。粗略地说,指数告诉您该点需要向左移动 2 个位置。这对于任何其他数字系统都完全相同。顺便说一句,指数也可以是正数,例如数字的表示法125000是尾数125和指数3。

    也就是说,数据结构可能如下所示

    ulong mantissa;
    ulong exponent;
    

    由于指数取决于数字系统的基数,因此 IEEE-754 假定它是十进制的。如果您打算将指数存储在另一个数字系统中,则还必须将其相加。

    ulong base;
    

    从数学上来说

    number = mantissa * (base ^ exponent)
    

    这是您可以构建逻辑的地方。

    至于数学运算,你认为将 3 个 bigint 粘合在一起就能成功,这是徒劳的。

    要对两个数字执行数学运算,必须将它们化简为共同指数,以便尾数不会四舍五入。例如,1.25 + 3this 位于125 + 300给定的尾数中, 和1.25 + 300this 分别位于12500 + 30000。也就是说,您需要对两个指数进行足够的加或减,以使它们的最小值变为0。然后对结果进行指数归一化以获得最佳的 mmantissa,右侧没有零。

    单独存储整数和小数部分(定点数)的方法也是可以接受的,但在我看来,实现起来更困难,因为您将不得不努力解决小数部分的准确性,因为最大小数部分的值必须等于数字系统的基数减一的数字,并在规定的精度允许的范围内重复多次。也就是说,对于ulong十进制系统,这9999999999999999999是 19 个 9。对于不同的数字系统,会有不同的数字,依此类推。也就是说,即使在定点数的存储选项中,也涉及到数字系统,并且这种格式的处理算法要复杂得多。因此,处理器使用更简单的系统——浮点和指数。

    • 0
  2. Best Answer
    Тихирун Ррр
    2024-06-11T03:17:54Z2024-06-11T03:17:54Z

    我能够解决这个问题。问题在于将存储的数字转换为文本(即特定分母)时。它被表示为 ulong,并向其写入 1 << 64,这将 1 变回 1。我将类型更改为 BigInteger,现在一切正常。现在看起来像这样

        private static string ConvertFractionalPartToBaseN(BigInteger fractionalPart, int n, int accuracy)
        {
            string result = "";
            BigInteger denominator = new BigInteger(1) << 64; // 2^64
            for (int i = 0; i < accuracy; i++)  // ограничим вывод accuracy разрядами для дробной части
            {
                fractionalPart *= n;
                BigInteger digit = fractionalPart / denominator;
                result += GetCharFromNumber(digit);
                fractionalPart %= denominator;
            }
            return result.TrimEnd('0').PadRight(1, '0'); // удалим нули в конце
        }
        ```
    
    • 0

相关问题

  • 使用嵌套类导出 xml 文件

  • 分层数据模板 [WPF]

  • 如何在 WPF 中为 ListView 手动创建列?

  • 在 2D 空间中,Collider 2D 挂在玩家身上,它对敌人的重量相同,我需要它这样当它们碰撞时,它们不会飞向不同的方向。统一

  • 如何在 c# 中使用 python 神经网络来创建语音合成?

  • 如何知道类中的方法是否属于接口?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5