簡體   English   中英

將浮點數轉換為char []而不分配內存

[英]Convert a float to char[] without memory allocation

您知道如何在不分配任何內存的情況下將float轉換為chars緩沖區嗎?

=>我只是想重新做與float.ToString()一樣的事情; 所以我可以將結果放入緩沖區,而不是分配字符串

我寫了一個函數,但是它不能很好地處理“四舍五入”:

  • 39.71變成“ 39.709996”
  • 39.71001變為“ 39.710004”

這是因為39.71作為浮點數是對內存中存儲的值39.709996的舍入。 通過對函數進行四舍五入,我可以輕松得出如下結果:

  • 39.71變為“ 39.71”
  • 39.71001變為“ 39.71”

這也不是什么float.ToString() ,因為我想保持與float.ToString()完全相同的算法,該算法設法編寫“ 39.71”和“ 39.71001”

您知道這個float.ToString()如何工作嗎?

我的目標很精確:我想在一個很大的字符串中附加大量的float(與其他類型混合),並在最后只分配一次此字符串,以避免過多的垃圾回收。 因此,我確實需要將float轉換為char數組(無論確切的類型格式,只有不可變的字符串)

您可以致電C stdlib sprintf()和朋友來解決大多數格式和數據問題。 有關示例,請參見https://stackoverflow.com/a/2479210/3150802 通過評估sprintf()的返回值來跟蹤打印位置(即char數組的索引sprintf()將很重要。

跨越管理/非管理邊界會不可避免地帶來一些性能損失。 一種可能的緩解策略是減少此類交叉的次數,例如,通過編寫一個C包裝函數,該函數可以接收大量的float並使用s*printf()一次性將其全部寫入。

如果數據浮點數和地址在兩個方面都是位相同的,那么對於數據封送(即CLI和本機表示形式之間的來回轉換)的潛在損失可能不會像浮點數和地址這樣的POD產生問題。

從您的評論看來,您希望能夠將許多浮點數(和其他值類型)格式化為非常大的字符數組,而不必進行大量的內存分配。

不可能避免所有內存分配,但是可以使用StringBuilder.AppendFormat()StringBuilder.CopyTo()來最小化它們。

如果您對最終char數組的最大長度有所了解,則可以初始化一個StringBuilder ,其容量足以容納它。 這可能會減少內存分配的數量,但是如果您使緩沖區過大,則會浪費內存。

代碼如下所示:

int capacity = 8192; // If you have some idea of the final string length.
var sb = new StringBuilder(capacity);

for (float x = 0; x < 1000; x += 1.2345f)
    sb.AppendFormat(", {0}", x);

char[] array = new char[sb.Length];

sb.CopyTo(0, array, 0, sb.Length); // Now array[] contains the result.

請注意,這里的緩沖區分配的最小數量為兩個:一個為StringBuilder使用的內部緩沖區,另一個為char []數組。

但是,很有可能在幕后進行許多其他的小分配-但是由於GC的工作方式,它們不太可能進入任何第1代收藏中,因此不太可能導致性能下降。問題。

由於Marc Gravell提供的float.ToString()源代碼,以下是我最終編寫的解決方案。

它經過了簡化,但目前看來效果很好(也許我錯過了一些特殊情況)。 我看到的唯一主要區別是,像5.34E-05這樣的很小的浮點數基本上將被寫為0.0000534(實際上,我更喜歡這樣)

有關信息,請參見我的完整StringFast類(Unity C#代碼): http ://pastebin.com/HqAw2pTG。 以及一些使用它的測試: http : //pastebin.com/brynBFyC

該測試運行1000次以下操作:4個追加(2個字符串,一個浮點數和一個int)和1個字符串替換。 我使用帶有+和Concat()的字符串,使用StringBuilder以及我的StringFast類來運行測試。 當然,對於最后兩個,我不會每次都重新創建它們。

以下是結果以及內存分配和時間:

  • 字符串(+):302.7KB,1.75ms
  • 字符串(.concat):302.7KB,1.85ms
  • StringBuilder:259.8KB,1.81ms
  • StringFast:58.6KB,1.68ms

如果我用100個浮點數的串聯代替5個操作:

  • 字符串(+):36.8MB,116.19ms
  • 字符串(.concat):36.8MB,116.19ms
  • StringBuilder:6.0MB,63.26ms
  • StringFast:0.6MB,51.09ms

如您所見,StringBuilder並不是很好,特別是當字符串上只有幾個操作時。 StringFast類的分配僅由我做的最終ToString()引起(以便能夠將字符串與其他函數一起使用)

這是將float轉換為char數組的代碼:

///<summary>Append a float without memory allocation.</summary>
public StringFast Append( float valueF )
{
    double value = valueF;
    m_isStringGenerated = false;
    ReallocateIFN( 32 ); // Check we have enough buffer allocated to handle any float number

    // Handle the 0 case
    if( value == 0 )
    {
        m_buffer[ m_bufferPos++ ] = '0';
        return this;
    }

    // Handle the negative case
    if( value < 0 )
    {
        value = -value;
        m_buffer[ m_bufferPos++ ] = '-';
    }

    // Get the 7 meaningful digits as a long
    int nbDecimals = 0;
    while( value < 1000000 )
    {
        value *= 10;
        nbDecimals++;
    }
    long valueLong = (long)System.Math.Round( value );

    // Parse the number in reverse order
    int nbChars = 0;
    bool isLeadingZero = true;
    while( valueLong != 0 || nbDecimals >= 0 )
    {
        // We stop removing leading 0 when non-0 or decimal digit
        if( valueLong%10 != 0 || nbDecimals <= 0 )
            isLeadingZero = false;

        // Write the last digit (unless a leading zero)
        if( !isLeadingZero )
            m_buffer[ m_bufferPos + (nbChars++) ] = (char)('0' + valueLong%10);

        // Add the decimal point
        if( --nbDecimals == 0 && !isLeadingZero )
            m_buffer[ m_bufferPos + (nbChars++) ] = '.';

        valueLong /= 10;
    }
    m_bufferPos += nbChars;

    // Reverse the result
    for( int i=nbChars/2-1; i>=0; i-- )
    {
        char c = m_buffer[ m_bufferPos-i-1 ];
        m_buffer[ m_bufferPos-i-1 ] = m_buffer[ m_bufferPos-nbChars+i ];
        m_buffer[ m_bufferPos-nbChars+i ] = c;
    }

    return this;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM