我目前确实有类似的问题,但我不仅需要比例,还需要尾数作为整数。根据上面的解决方案,请在下面找到我能想到的最快的解决方案。统计数据:“ViaBits”在我的机器上进行 7,000,000 次检查需要 2,000 毫秒。“ViaString”同样的任务需要 4,000 毫秒。
public class DecimalInfo {
public BigInteger Mantisse { get; private set; }
public SByte Scale { get; private set; }
private DecimalInfo() {
}
public static DecimalInfo Get(decimal d) {
//ViaBits is faster than ViaString.
return ViaBits(d);
}
public static DecimalInfo ViaBits(decimal d) {
//This is the fastest, I can come up with.
//Tested against the solutions from http://stackoverflow.com/questions/763942/calculate-system-decimal-precision-and-scale
if (d == 0) {
return new DecimalInfo() {
Mantisse = 0,
Scale = 0,
};
} else {
byte scale = (byte)((Decimal.GetBits(d)[3] >> 16) & 31);
//Calculating the mantisse from the bits 0-2 is slower.
if (scale > 0) {
if ((scale & 1) == 1) {
d *= 10m;
}
if ((scale & 2) == 2) {
d *= 100m;
}
if ((scale & 4) == 4) {
d *= 10000m;
}
if ((scale & 8) == 8) {
d *= 100000000m;
}
if ((scale & 16) == 16) {
d *= 10000000000000000m;
}
}
SByte realScale = (SByte)scale;
BigInteger scaled = (BigInteger)d;
//Just for bigger steps, seems reasonable.
while (scaled % 10000 == 0) {
scaled /= 10000;
realScale -= 4;
}
while (scaled % 10 == 0) {
scaled /= 10;
realScale--;
}
return new DecimalInfo() {
Mantisse = scaled,
Scale = realScale,
};
}
}
public static DecimalInfo ViaToString(decimal dec) {
if (dec == 0) {
return new DecimalInfo() {
Mantisse = 0,
Scale = 0,
};
} else {
//Is slower than "ViaBits".
string s = dec.ToString(CultureInfo.InvariantCulture);
int scale = 0;
int trailingZeros = 0;
bool inFraction = false;
foreach (char c in s) {
if (inFraction) {
if (c == '0') {
trailingZeros++;
} else {
trailingZeros = 0;
}
scale++;
} else {
if (c == '.') {
inFraction = true;
} else if (c != '-') {
if (c == '0'){
trailingZeros ++;
} else {
trailingZeros = 0;
}
}
}
}
if (inFraction) {
return new DecimalInfo() {
Mantisse = BigInteger.Parse(s.Replace(".", "").Substring(0, s.Length - trailingZeros - 1)),
Scale = (SByte)(scale - trailingZeros),
};
} else {
return new DecimalInfo() {
Mantisse = BigInteger.Parse(s.Substring(0, s.Length - trailingZeros)),
Scale = (SByte)(scale - trailingZeros),
};
}
}
}
}