C#从浮点变量中获取数字

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1040707/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 06:45:46  来源:igfitidea点击:

C# get digits from float variable

c#.netfloating-point

提问by Karsten

I have a float variable and would like to get only the part after the comma, so if I have 3.14. I would like to get 14 as an integer. How can I do that?

我有一个浮点变量,只想得到逗号后面的部分,所以如果我有 3.14. 我想得到 14 作为整数。我怎样才能做到这一点?

采纳答案by David

The cheating way to do it is:

作弊的方法是:

    private Int32 FractionalPart(double n)
    {
        string s = n.ToString("#.#########", System.Globalization.CultureInfo.InvariantCulture);
        return Int32.Parse(s.Substring(s.IndexOf(".") + 1));
    }

edit2: OK OK OK OK. Here is the most paranoid never fail version I can come up with. This will return the first 9 digits (or less, if there aren't that many) of the decimal portion of the floating point number. This is guaranteed to not overflow an Int32. We use the invariant culture so we know that we can use a period as the decimal separator.

编辑2:好的好的好的好的。这是我能想出的最偏执的永不失败版本。这将返回浮点数小数部分的前 9 位(或更少,如果没有那么多)。这保证不会溢出 Int32。我们使用不变文化,所以我们知道我们可以使用句点作为小数点分隔符。

回答by Michael

You can subtract the integer portion from the value itself to retrieve the fractional part.

您可以从值本身中减去整数部分以检索小数部分。

float x = 3.14
float fractionalPortion = x - Math.Truncate(x);

You can then multiply it to get the fractional part represented as an integer at whatever precision you'd like.

然后,您可以将它相乘,以您想要的任何精度将小数部分表示为整数。

Mapping the fractional portion to an integer has some challenges - many floating point numbers cannot be represented as a base-10 integer, and thus may require more digits to represent than an integer can support.

将小数部分映射到整数有一些挑战 - 许多浮点数不能表示为以 10 为基数的整数,因此可能需要比整数可以支持的更多数字来表示。

Also, what of the case of numbers like 3.1 and 3.01? Mapping directly to an integer would both result in 1.

另外,像 3.1 和 3.01 这样的数字怎么办?直接映射到整数都会导致 1。

回答by jitter

float x = 3.14
int fractionalPortionAsInt = (int) (100 * (x - Math.Floor(x)));

回答by Will Eddins

To suggest something different than the others, an extension method (with a method similar to David's):

为了提出与其他人不同的建议,一种扩展方法(使用类似于大卫的方法):

public static int GetDecimalAsInt(this float num)
{
    string s = n.ToString();
    int separator = s.IndexOf(System.Globalization.CultureInfo.CurrentUICulture.NumberFormat.NumberDecimalSeparator);
    return int.Parse(s.Substring(separator + 1));
}

// Usage:
float pi = 3.14;
int digits = pi.GetDecimalAsInt();

Edit:I didn't use the "best" answer, because it omitted the hardest part, which is converting an arbitrary decimal number, and did not work for negative numbers. I added the correction requested in David's answer.

编辑:我没有使用“最佳”答案,因为它省略了最难的部分,即转换任意十进制数,并且不适用于负数。我添加了大卫回答中要求的更正。

回答by David

Here's the "noncheating" answer:

这是“非作弊”的答案:

double n = 3.14;
const double precision = 0.000001;

// we don't handle negative numbers very well
if (n < 0)
    n = 0 - n;

// remove the integer part of n
n -= Math.Floor(n);
int result = 0;
while (n > precision)
{
    // move 1/10th digit of n into 1's place
    n *= 10;
    // get that digit
    int digit = (int)Math.Floor(n);
    // shift result left and add digit to it
    result = result * 10 + digit;
    // remove 1's digit from n
    n -= digit;
}

// answer is in result;

We use precision instead of 0 to make up for the fact that floating point numbers don't work very well with decimal numbers. You can adjust it to suit your application. This is why I think the "cheating" string way is actually better.

我们使用精度而不是 0 来弥补浮点数不能很好地处理十进制数的事实。您可以调整它以适合您的应用程序。这就是为什么我认为“欺骗”字符串方式实际上更好的原因。

回答by jitter

Actually all solutions until now are wrong as they don't consider that using Math.Floor()will do the wrong thing if the value is negative (e.g. Math.Floor(-2.8) -> -3)

实际上,到目前为止所有的解决方案都是错误的,因为他们不认为Math.Floor()如果值为负, using会做错事(例如 Math.Floor(-2.8) -> -3)

double number = -1234.56789;
decimal numberM = Convert.ToDecimal(number);
decimal fraction = Math.Abs(numberM - Math.Truncate(numberM));
int mantissa = Convert.ToInt32((double)fraction * Math.Pow(10, fraction.ToString().Length - 2));

回答by Tyler Collier

Here's another version that also tells how many digits are part of the fractional make-up, which I needed.

这是另一个版本,它也说明了我需要的分数构成的一部分。

public static int GetFractionalPartAsInt(decimal n, out int numOfFractionalDigits)
{
  n -= Math.Truncate(n);
  n = Math.Abs(n);

  int numOfFractionalDigitsValue = 0;
  // When n != Math.Truncate(n), we have seen all fractional decimals.
  while (n != Math.Truncate(n))
  {
    n *= 10;
    numOfFractionalDigitsValue++;
  }

  numOfFractionalDigits = numOfFractionalDigitsValue;

  return (int)n;
}

It's similar in idea to David's answer (his non-cheating version). However, I used the decimal type instead of double, which slows things down, but improves accuracy. If I convert David's (again, non-cheating version) answer to use a decimal type (in which case his "precision" variable can be changed to the constant zero), my answer runs about 25% faster. Note that I also changed his code to provide the number of fractional digits in my testing.

这与大卫的答案(他的非作弊版本)的想法相似。但是,我使用了 decimal 类型而不是 double,这会减慢速度,但提高了准确性。如果我将大卫的(再次,非作弊版本)答案转换为使用十进制类型(在这种情况下,他的“精度”变量可以更改为常量零),我的答案运行速度大约快 25%。请注意,我还更改了他的代码以在我的测试中提供小数位数。

回答by Tyler Collier

Try

尝试

float n = 3.14f;
int fractionalPart = new System.Version(n.ToString()).Minor;

David's "cheating version" answer doesn't seem to be very popular at the moment, but after looking into this for the better part of the day, I found the System.Version class. It has a constructor which takes a string. Using Reflector, I saw that it works by splitting the string into an array. I ran a test getting the fractional part of the arbitrary number 1234567891.1234567891m. With 1,000,000 iterations, it was 50% faster than the other answer I posted in spite of the fact that I first had to convert the decimal number to a stringfor the sake of the Version constructor. So David is getting a bad break when using a string conversion concept seems to be a bright way to go. Microsoft did.

David 的“作弊版本”答案目前似乎不是很受欢迎,但是在一天中大部分时间研究这个之后,我找到了 System.Version 类。它有一个接受字符串的构造函数。使用 Reflector,我看到它通过将字符串拆分为数组来工作。我运行了一个测试,得到了任意数字 1234567891.1234567891m 的小数部分。通过 1,000,000 次迭代,它比我发布的另一个答案快 50%,尽管我首先必须为了 Version 构造函数将十进制数转换为字符串。因此,当使用字符串转换概念似乎是一条光明的道路时,David 遇到了麻烦。微软做到了。

回答by Keith

This will result in some odd unpredictable values.

这将导致一些奇怪的不可预测的值。

Floating point numbers are not stored as a decimal - the exponent part is a power of 2, not 10.

浮点数不存储为小数 - 指数部分是 2 的幂,而不是 10。

This means that some numbers (for instance 1.1) can't be accurately expressed as a float (1.1 ends up something like 1.099999999998)

这意味着某些数字(例如 1.1)不能准确地表示为浮点数(1.1 最终类似于 1.099999999998)

The problem is that for some numbers the starting number may not be one of these while the decimal part on its own might be.

问题是对于某些数字,起始数字可能不是其中之一,而小数部分本身可能是。

So your number is x.y

所以你的号码是xy

You get the integer part x

你得到整数部分 x

You do x.y - x to get 0.y

你做 xy - x 得到 0.y

Sometimes x.y can be expressed as a float and 0.y can't, so rather than get y you'll get some big value with lots of 0s or 9s in it.

有时 xy 可以表示为浮点数而 0.y 不能表示,因此,与其得到 y,您还会得到一些包含大量 0 或 9 的大值。

@David's 'cheating' way is actually the best way - least prone to this issue anyway.

@David 的“作弊”方式实际上是最好的方式 - 无论如何最不容易出现这个问题。

However I'd look at why you need to do this - floats are great for very fast maths, but a bit rubbish for accuracy. If accuracy is important use a decimaltype instead - that type guarantees that the precise value is stored, but at the cost of slower maths.

但是我会看看为什么你需要这样做 - 浮点数对于非常快的数学非常有用,但对于准确性来说有点垃圾。如果准确性很重要,请改用decimal类型 - 该类型保证存储精确的值,但以较慢的数学为代价。

回答by dave

I saw a and fast way to convert floats/doubles to integers representative of their digits using a bitmask and the GetBits method... It only works if the results fit into a 32 bit integer, but it's still really slick... I can't take credit for it, but have a look:

我看到了一种使用位掩码和 GetBits 方法将浮点数/双精度数转换为代表其数字的整数的快速方法......它仅在结果适合 32 位整数时才有效,但它仍然非常光滑......我可以不相信它,但看看:

http://stsdb.com/showthread.php?t=58&p=285&viewfull=1#post285

http://stsdb.com/showthread.php?t=58&p=285&viewfull=1#post285