Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 非指数格式浮点_C#_String_Floating Point - Fatal编程技术网

C# 非指数格式浮点

C# 非指数格式浮点,c#,string,floating-point,C#,String,Floating Point,我有一个UTF-8格式的数据文件,其中包含数千个浮点数。在设计时,开发人员决定省略指数符号中的“e”以节省空间。因此,数据如下所示: 1.85783+16 0.000000+0 1.900000+6-3.855418-4 1.958263+6 7.836995-4 -2.000000+6 9.903130-4 2.100000+6 1.417469-3 2.159110+6 1.655700-3 2.200000+6 1.813662-3-2.250000+6-1.998687-3 2.30

我有一个UTF-8格式的数据文件,其中包含数千个浮点数。在设计时,开发人员决定省略指数符号中的“e”以节省空间。因此,数据如下所示:

 1.85783+16 0.000000+0 1.900000+6-3.855418-4 1.958263+6 7.836995-4
-2.000000+6 9.903130-4 2.100000+6 1.417469-3 2.159110+6 1.655700-3
 2.200000+6 1.813662-3-2.250000+6-1.998687-3 2.300000+6 2.174219-3
 2.309746+6 2.207278-3 2.400000+6 2.494469-3 2.400127+6 2.494848-3
-2.500000+6 2.769739-3 2.503362+6 2.778185-3 2.600000+6 3.020353-3
 2.700000+6 3.268572-3 2.750000+6 3.391230-3 2.800000+6 3.512625-3
 2.900000+6 3.750746-3 2.952457+6 3.872690-3 3.000000+6 3.981166-3
 3.202512+6 4.437824-3 3.250000+6 4.542310-3 3.402356+6 4.861319-3
问题是float.Parse()无法使用此格式。我的中间解决方案是

    protected static float ParseFloatingPoint(string data)
    {

        int signPos;
        char replaceChar = '+';

        // Skip over first character so that a leading + is not caught
        signPos = data.IndexOf(replaceChar, 1);

        // Didn't find a '+', so lets see if there's a '-'
        if (signPos == -1)
        {
            replaceChar = '-';
            signPos = data.IndexOf('-', 1);
        }

        // Found either a '+' or '-'
        if (signPos != -1)
        {
            // Create a new char array with an extra space to accomodate the 'e'
            char[] newData = new char[EntryWidth + 1];

            // Copy from string up to the sign
            for (int i = 0; i < signPos; i++)
            {
                newData[i] = data[i];
            }

            // Replace the sign with an 'e + sign'
            newData[signPos] = 'e';
            newData[signPos + 1] = replaceChar;

            // Copy the rest of the string
            for (int i = signPos + 2; i < EntryWidth + 1; i++)
            {
                newData[i] = data[i - 1];
            }

            return float.Parse(new string(newData), NumberStyles.Float, CultureInfo.InvariantCulture);
        }
        else
        {
            return float.Parse(data, NumberStyles.Float, CultureInfo.InvariantCulture);
        }
    }
受保护的静态浮点解析浮点(字符串数据)
{
int signPos;
char replaceChar='+';
//跳过第一个字符,以便不捕获前导+字符
signPos=data.IndexOf(replaceChar,1);
//没有找到“+”,所以让我们看看是否有“-”
如果(signPos==-1)
{
replaceChar='-';
signPos=data.IndexOf('-',1);
}
//找到了“+”或“-”
如果(signPos!=-1)
{
//创建一个具有额外空间的新字符数组以容纳“e”
char[]newData=newchar[EntryWidth+1];
//从字符串复制到符号
对于(int i=0;i
我不能调用简单的String.Replace(),因为它将替换任何前导的负号。我可以使用子字符串,但我会制作很多额外的字符串,我很关心性能

有人有更优雅的解决方案吗

string test = "1.85783-16";
char[] signs = { '+', '-' };

int decimalPos = test.IndexOf('.');
int signPos = test.LastIndexOfAny(signs); 

string result = (signPos > decimalPos) ?
     string.Concat(
         test.Substring(0, signPos), 
         "E", 
         test.Substring(signPos)) : test;

float.Parse(result).Dump();  //1.85783E-16
我在这里使用的思想确保小数点位于符号之前(这样可以避免指数丢失时出现任何问题),以及使用LastIndexOf()从后面开始工作(确保存在指数时有指数)。如果可能有前缀“+”,则第一个If需要包括
| | signPos

其他结果:

"1.85783" => "1.85783"; //Missing exponent is returned clean
"-1.85783" => "-1.85783"; //Sign prefix returned clean
"-1.85783-3" => "-1.85783e-3" //Sign prefix and exponent coexist peacefully.

根据注释,对该方法的测试只显示了5%的性能命中率(在避免使用String.Format()之后,我应该记得这是非常糟糕的)。我认为代码要清楚得多:只需要做一个决定。

您是否可以使用正则表达式来识别每个事件

以下是有关合适表达式的一些信息:


就速度而言,您最初的解决方案是我迄今为止尝试过的最快的解决方案(@Godeke's是非常接近的第二个)@Godeke的可读性很强,只是性能下降了一小部分。再加上一些稳健性检查,他的目标可能是长期目标。就稳健性而言,您可以将其添加到您的中,如下所示:

static char[] signChars = new char[] { '+', '-' };

static float ParseFloatingPoint(string data)
{
    if (data.Length != EntryWidth)
    {
        throw new ArgumentException("data is not the correct size", "data");
    }
    else if (data[0] != ' ' && data[0] != '+' && data[0] != '-')
    {
        throw new ArgumentException("unexpected leading character", "data");
    }

    int signPos = data.LastIndexOfAny(signChars);

    // Found either a '+' or '-'
    if (signPos > 0)
    {
        // Create a new char array with an extra space to accomodate the 'e'
        char[] newData = new char[EntryWidth + 1];

        // Copy from string up to the sign
        for (int ii = 0; ii < signPos; ++ii)
        {
            newData[ii] = data[ii];
        }

        // Replace the sign with an 'e + sign'
        newData[signPos] = 'e';
        newData[signPos + 1] = data[signPos];

        // Copy the rest of the string
        for (int ii = signPos + 2; ii < EntryWidth + 1; ++ii)
        {
            newData[ii] = data[ii - 1];
        }

        return Single.Parse(
            new string(newData),
            NumberStyles.Float,
            CultureInfo.InvariantCulture);
    }
    else
    {
        Debug.Assert(false, "data does not have an exponential? This is odd.");
        return Single.Parse(data, NumberStyles.Float, CultureInfo.InvariantCulture);
    }
}

为什么不编写一个简单的脚本来重新格式化数据文件一次,然后使用
float.Parse()


您说的是“数千”个浮点数,因此即使是非常简单的方法也会很快完成(如果您说的是“万亿”,我会更犹豫),而只需运行一次的代码(几乎)永远不会对性能造成影响。当然,运行该程序所需的时间比发布问题所需的时间要少,而且出错的机会也要小得多。

感谢Godeke不断改进的编辑

最后,我更改了解析函数的参数,使其采用char[]而不是字符串,并使用您的基本前提得出以下结论

    protected static float ParseFloatingPoint(char[] data)
    {
        int decimalPos = Array.IndexOf<char>(data, '.');
        int posSignPos = Array.LastIndexOf<char>(data, '+');
        int negSignPos = Array.LastIndexOf<char>(data, '-');

        int signPos = (posSignPos > negSignPos) ? posSignPos : negSignPos;

        string result;
        if (signPos > decimalPos)
        {
            char[] newData = new char[data.Length + 1];
            Array.Copy(data, newData, signPos);
            newData[signPos] = 'E';
            Array.Copy(data, signPos, newData, signPos + 1, data.Length - signPos);
            result = new string(newData);
        }
        else
        {
            result = new string(data);
        }

        return float.Parse(result, NumberStyles.Float, CultureInfo.InvariantCulture);
    }
受保护的静态浮点解析浮点(char[]数据)
{
int decimalPos=Array.IndexOf(数据“.”);
int posSignPos=Array.LastIndexOf(数据“+”);
int negSignPos=Array.LastIndexOf(数据“-”);
int signPos=(posSignPos>negSignPos)?posSignPos:negSignPos;
字符串结果;
如果(signPos>decimalPos)
{
char[]newData=newchar[data.Length+1];
数组.Copy(数据、新数据、signPos);
newData[signPos]=“E”;
Array.Copy(data,signPos,newData,signPos+1,data.Length-signPos);
结果=新字符串(newData);
}
其他的
{
结果=新字符串(数据);
}
返回float.Parse(result,NumberStyles.float,CultureInfo.InvariantCulture);
}

我将函数的输入从string更改为char[],因为我想离开ReadLine()。我假设这比创建大量字符串性能更好。相反,我从数据文件中获取固定数量的字节(因为它总是11个字符宽度的数据),将字节[]转换为字符[],然后执行上述处理以转换为浮点

对他的语料库的基准测试扩展到25k行,显示大约40%的速度减慢,主要是由于String.Format.Hmmm。与标准连接相比,我看不到任何东西接近于这么大的速度降低,尽管速度较慢。尽管如此,编辑为串联。您是正确的,切换到String.Concat(a,b,c)大大提高了您的性能,仅比Brian的性能低5%。您可以使用
LastIndexOfAny(新[]{'+','-'})
在一次点击中找到
signPos
。您真的每次都无条件地将
test
分配给
result
?如果是这样,请尝试更改内容,以便仅在
条件不满足时执行该赋值:
字符串结果;如果(signPos>decimalPos)结果=string.Concat(…);其他结果=试验从内部了解一些信息,此输入文件本身无法修改。我非常感谢基准测试。最后,我认为你对Godeke更好的长期解决方案的看法是正确的。我
    protected static float ParseFloatingPoint(char[] data)
    {
        int decimalPos = Array.IndexOf<char>(data, '.');
        int posSignPos = Array.LastIndexOf<char>(data, '+');
        int negSignPos = Array.LastIndexOf<char>(data, '-');

        int signPos = (posSignPos > negSignPos) ? posSignPos : negSignPos;

        string result;
        if (signPos > decimalPos)
        {
            char[] newData = new char[data.Length + 1];
            Array.Copy(data, newData, signPos);
            newData[signPos] = 'E';
            Array.Copy(data, signPos, newData, signPos + 1, data.Length - signPos);
            result = new string(newData);
        }
        else
        {
            result = new string(data);
        }

        return float.Parse(result, NumberStyles.Float, CultureInfo.InvariantCulture);
    }