2011-07-24 25 views
3

在所有基礎類型都是字符串的數據格式中,必須將數字類型轉換爲可以按字母順序進行比較的標準化字符串格式。例如,如果不存在負數,則值27short可表示爲00027將System.Double表示爲可排序字符串的最佳方式是什麼?

double表示爲字符串的最佳方式是什麼?在我的情況下,我可以忽略負面情況,但我會好奇你在這兩種情況下如何表現雙倍。

UPDATE

基於喬恩斯基特的建議,我現在用的這個,雖然我不是100%肯定它會正常工作:

static readonly string UlongFormatString = new string('0', ulong.MaxValue.ToString().Length); 

public static string ToSortableString(this double n) 
{ 
    return BitConverter.ToUInt64(BitConverter.GetBytes(BitConverter.DoubleToInt64Bits(n)), 0).ToString(UlongFormatString); 
} 

public static double DoubleFromSortableString(this string n) 
{ 
    return BitConverter.Int64BitsToDouble(BitConverter.ToInt64(BitConverter.GetBytes(ulong.Parse(n)), 0)); 
} 

更新2

我已經證實喬恩懷疑什麼 - 陰性不能使用這種方法。下面是一些示例代碼:

void Main() 
{ 
    var a = double.MaxValue; 
    var b = double.MaxValue/2; 
    var c = 0d; 
    var d = double.MinValue/2; 
    var e = double.MinValue; 
    Console.WriteLine(a.ToSortableString()); 
    Console.WriteLine(b.ToSortableString()); 
    Console.WriteLine(c.ToSortableString()); 
    Console.WriteLine(d.ToSortableString()); 
    Console.WriteLine(e.ToSortableString()); 
} 

static class Test 
{ 
    static readonly string UlongFormatString = new string('0', ulong.MaxValue.ToString().Length); 
    public static string ToSortableString(this double n) 
    { 
     return BitConverter.ToUInt64(BitConverter.GetBytes(BitConverter.DoubleToInt64Bits(n)), 0).ToString(UlongFormatString); 
    } 
} 

將會產生以下的輸出:

09218868437227405311 
09214364837600034815 
00000000000000000000 
18437736874454810623 
18442240474082181119 

預期顯然沒有排序。

更新3

下面的接受的答案是正確的。多謝你們!

+5

爲什麼要排序字符串(=表示法)而不是實際值?這幾乎總是一個壞主意。 –

+0

@Konrad我在問題中解釋了這一點 - 「所有基礎類型都是字符串」。特別是在我的情況下,我使用的是Lucene,但也有其他需要按字母順序排序的格式。 –

回答

5

考慮到巨大的範圍(double.MaxValue是1.7976931348623157E + 308),填充對於雙打來說可能相當尷尬。

字符串表示仍然必須是人類可讀的,或只是可逆?

,給出了一個可逆轉換導致相當短的字符串表示保留字典序 - 但它不會是在所有顯而易見什麼double值剛剛從字符串了。

編輯:不要單獨使用BitConverter.DoubleToInt64Bits。這顛倒了負值的排序。

我敢肯定,你可以執行使用DoubleToInt64Bits,然後一些位變換這種轉換,但不幸的是,我不能讓它的工作現在,和我有三個孩子誰是不顧一切地去公園...


爲了使一切正確排序,負數需要被存儲在那些補格式,而不是符號幅度(否則底片和排序相反的順序陽性)和符號位需要翻轉(使負面排序少於正面)。此代碼應該做的伎倆:

static ulong EncodeDouble(double d) 
{ 
    long ieee = System.BitConverter.DoubleToInt64Bits(d); 
    ulong widezero = 0; 
    return ((ieee < 0)? widezero: ((~widezero) >> 1))^(ulong)~ieee; 
} 

static double DecodeDouble(ulong lex) 
{ 
    ulong widezero = 0; 
    long ieee = (long)(((0 <= (long)lex)? widezero: ((~widezero) >> 1))^~lex); 
    return System.BitConverter.Int64BitsToDouble(ieee); 
} 

示範這裏:http://ideone.com/JPNPY

下面是完整的解決方案,並從字符串:

static string EncodeDouble(double d) 
{ 
    long ieee = System.BitConverter.DoubleToInt64Bits(d); 
    ulong widezero = 0; 
    ulong lex = ((ieee < 0)? widezero: ((~widezero) >> 1))^(ulong)~ieee; 
    return lex.ToString("X16"); 
} 

static double DecodeDouble(string s) 
{ 
    ulong lex = ulong.Parse(s, System.Globalization.NumberStyles.AllowHexSpecifier); 
    ulong widezero = 0; 
    long ieee = (long)(((0 <= (long)lex)? widezero: ((~widezero) >> 1))^~lex); 
    return System.BitConverter.Int64BitsToDouble(ieee); 
} 

示範:http://ideone.com/pFciY

+0

我知道這個問題表示可以不處理負面情況,但是無論如何,在你的回答中值得一提的是下一位讀者。當然,人們可以將一個可讀的表示添加到原始位的Base64(或類似的)編碼中。 –

+0

@Ben:我不認爲它們真的受到了影響 - 如果你有一個處理負Int64值的字符串格式,它對於負雙打也能正常工作。 –

+0

檢查排序順序。 –

1

我相信,修改後的科學記數法,首先指數,然後用下劃線表示正數,然後按照詞彙順序排列按照數字順序排列。

如果你願意,你甚至可以追加正常表現,因爲後綴不會影響排序。

例子

E000M3 +3.0 
E001M2.7 +27.0 

不幸的是,它不爲任何負數或負指數的工作。您可以爲指數引入一個偏差,如IEEE格式在內部使用。

0

事實證明...的org.apache.solr.util包中包含NumberUtils類。這個類有靜態方法,可以完成將雙精度(和其他數據值)轉換爲可排序字符串(以及返回)所需的一切。這些方法不容易使用。幾點注意事項:

  1. 當然,NumberUtils是用Java(而不是c#)編寫的。我的猜測是,代碼可以轉換爲C#...但是,我不熟悉C#。該來源很容易在線獲得。
  2. 生成的字符串不可打印(完全)。
  3. 在代碼中的註釋表明,所有奇異的情況下,包括負數和無窮大,應能正常工作。
  4. 我沒有做任何的基準。不過,基於代碼的快速掃描,它應該是非常快的。下面

的代碼顯示需要完成使用這個庫的內容。

String key = NumberUtils.double2sortableStr(35.2); 
相關問題