소수점 앞의 자릿수 가져 오기
decimal
유형 변수가 있고 소수점 앞의 자릿수를 확인하고 싶습니다. 어떻게해야합니까? 예를 들어 467.45
를 반환해야합니다 3
.
변환하지 않는 솔루션 string
(이국적 문화의 경우 위험 할 수 있음) :
static int GetNumberOfDigits(decimal d)
{
decimal abs = Math.Abs(d);
return abs < 1 ? 0 : (int)(Math.Log10(decimal.ToDouble(abs)) + 1);
}
이 솔루션은 모든 십진수 값에 유효합니다.
최신 정보
사실이 솔루션은 예를 들어, 몇 가지 큰 값으로 작동하지 않습니다 : 999999999999998
, 999999999999999
, 9999999999999939
...
분명히 double
수학적 연산을 수행합니다.
잘못된 값을 검색하는 동안 나는 string
이 주제에서 제안한 기반 대안 을 사용하는 경향이 있습니다 . 저에게는 더 많은 사용 방법이 있습니다 (그러나 문화에 유의하십시오). 루프 기반 솔루션은 더 빠를 수 있습니다.
해설자 덕분에 나에게 부끄러워하고 교훈을 얻었습니다.
0이 될 때까지 숫자를 10으로 나눌 수도 있습니다. 흥미로운 점은 소수에 대한 수학적 연산이 소수를보다 적게 변환하고 길이를 반환하는 것보다 훨씬 느리다는 것입니다 (아래 벤치 마크 참조).
이 솔루션은 double 을 입력으로 취하는 수학 방법을 사용하지 않습니다 . 따라서 모든 작업은 소수로 수행되며 캐스팅이 필요하지 않습니다.
using System;
public class Test
{
public static void Main()
{
decimal dec = -12345678912345678912345678912.456m;
int digits = GetDigits(dec);
Console.WriteLine(digits.ToString());
}
static int GetDigits(decimal dec)
{
decimal d = decimal.Floor(dec < 0 ? decimal.Negate(dec) : dec);
// As stated in the comments of the question,
// 0.xyz should return 0, therefore a special case
if (d == 0m)
return 0;
int cnt = 1;
while ((d = decimal.Floor(d / 10m)) != 0m)
cnt++;
return cnt;
}
}
출력은 29
. 이 샘플을 실행 광고가 링크를 방문 하십시오 .
참고 : 일부 벤치 마크는 놀라운 결과를 보여줍니다 (10k 실행).
while ((d = decimal.Floor(d / 10m)) != 0m)
: 25mswhile ((d = d / 10m) > 1m)
: 32ms- 수학 이중 연산이있는 ToString : 3ms
- 십진수 연산이있는 ToString : 3ms
- BigInt ( @Heinzi의 답변 참조 ) : 2ms
또한 항상 동일한 값 대신 난수를 사용하여 (십진수를 소유로 변환 할 수있는 캐싱을 방지하기 위해) 많은 기반 방법이 훨씬 빠르다는 것을 보여줍니다.
나는 시도 할 것이다 :
Math.Truncate(467.45).ToString().Length
다른 문화와 음수 소수에 대해 이상한 결과를 얻지 좋습니다.
var myDecimal = 467.45m;
Math.Truncate(Math.Abs(myDecimal)).ToString(CultureInfo.InvariantCulture).Length
int
큰 숫자 (예 :)도 처리 할 수 있도록 캐스트 대신 다음을 선호합니다 decimal.MaxValue
.
Math.Truncate ( Math.Abs ( decValue ) ).ToString( "####" ).Length
decimal d = 467.45M;
int i = (int)d;
Console.WriteLine(i.ToString(CultureInfo.InvariantCulture).Length); //3
방법으로;
public static int GetDigitsLength(decimal d)
{
int i = int(d);
return i.ToString(CultureInfo.InvariantCulture).Length;
}
참고 : 먼저 소수점 부분이 더 큰지 확인해야합니다 . 참조 .Int32.MaxValue
OverflowException
long
대신 사용 int
하는 것이 더 좋은 방법입니다. 그러나long
( System.Int64
) 조차도 가능한 모든 decimal
값 을 담을만큼 크지 언어 .
Rawling이 언급했듯이 전체 부분에는 천 단위 구분 기호가 손상됩니다. 이런 식으로 내 번호 포함 여부를 완전히 무시하기 때문입니다.NumberFormatInfo.NumberGroupSeparator
그래서 숫자 만 얻는 것이 더 나은 접근 방식입니다. 처럼;
i.ToString().Where(c => Char.IsDigit(c)).ToArray()
다음은 재귀 적 예제입니다 (주로 재미를 위해).
void Main()
{
digitCount(0.123M); //0
digitCount(493854289.543354345M); //10
digitCount(4937854345454545435549.543354345M); //22
digitCount(-4937854345454545435549.543354345M); //22
digitCount(1.0M); //1
//approximately the biggest number you can pass to the function that works.
digitCount(Decimal.MaxValue + 0.4999999M); //29
}
int digitCount(decimal num, int count = 0)
{
//divided down to last digit, return how many times that happened
if(Math.Abs(num) < 1)
return count;
return digitCount(num/10, ++count); //increment the count and divide by 10 to 'remove' a digit
}
Math.Floor(Math.Log10((double)n) + 1);
갈 길입니다.
다음보다 클 수 있으므로 변환하는 int
것은 나쁘다 .decimal
int
Decimal.MaxValue = 79,228,162,514,264,337,593,543,950,335;
Int32.MaxValue = 2,147,483,647; //that is, hexadecimal 0x7FFFFFFF;
Math.Floor(n).ToString().Count();
수천 개의 존재하는 포함되어 있습니다.
더 작은 숫자에 대한 편견이 권한 부여와 같이 더 간단한 것을 사용할 수 있습니다.
두 가지 방법으로 분할하는 첫 번째 방법은 더 작은 인라인 될 수 있습니다.
성능은 Log10의 솔루션과 거의 동일하지만 반올림 오류가 없습니다. Log10을 사용하는 방법은 특히 1 백만 이상의 숫자에 대해 여전히 가장 빠 사용 (비트).
public static int CountNrOfDigitsIfs(decimal d) {
var absD = Math.Abs(d);
// 1
if (absD < 10M) return 1;
// 2
if (absD < 100M) return 2;
// 3
if (absD < 1000M) return 3;
// 4
if (absD < 10000M) return 4;
return CountNrOfDigitsIfsLarge(d);
}
private static int CountNrOfDigitsIfsLarge(decimal d) {
// 5
if (d < 100000M) return 5;
// 6
if (d < 1000000M) return 6;
// 7
if (d < 10000000M) return 7;
// 8
if (d < 100000000M) return 8;
// 9
if (d < 1000000000M) return 9;
// 10
if (d < 10000000000M) return 10;
// 11
if (d < 100000000000M) return 11;
// 12
if (d < 1000000000000M) return 12;
// 13
if (d < 10000000000000M) return 13;
// 14
if (d < 100000000000000M) return 14;
// 15
if (d < 1000000000000000M) return 15;
// 16
if (d < 10000000000000000M) return 16;
// 17
if (d < 100000000000000000M) return 17;
// 18
if (d < 1000000000000000000M) return 18;
// 19
if (d < 10000000000000000000M) return 19;
// 20
if (d < 100000000000000000000M) return 20;
// 21
if (d < 1000000000000000000000M) return 21;
// 22
if (d < 10000000000000000000000M) return 22;
// 23
if (d < 100000000000000000000000M) return 23;
// 24
if (d < 1000000000000000000000000M) return 24;
// 25
if (d < 10000000000000000000000000M) return 25;
// 26
if (d < 100000000000000000000000000M) return 26;
// 27
if (d < 1000000000000000000000000000M) return 27;
// 28
if (d < 10000000000000000000000000000M) return 28;
return 29; // Max nr of digits in decimal
}
이 코드는 다음 T4 템플릿을 사용하여 생성합니다.
<#
const int SIGNIFICANT_DECIMALS = 29;
const int SPLIT = 5;
#>
namespace Study.NrOfDigits {
static partial class DigitCounter {
public static int CountNrOfDigitsIfs(decimal d) {
var absD = Math.Abs(d);
<#
for (int i = 1; i < SPLIT; i++) { // Only 29 significant digits
var zeroes = new String('0', i);
#>
// <#= i #>
if (absD < 1<#= zeroes #>M) return <#= i #>;
<#
}
#>
return CountNrOfDigitsIfsLarge(d);
}
private static int CountNrOfDigitsIfsLarge(decimal d) {
<#
for (int i = SPLIT; i < SIGNIFICANT_DECIMALS; i++) { // Only 29 significant digits
var zeroes = new String('0', i);
#>
// <#= i #>
if (d < 1<#= zeroes #>M) return <#= i #>;
<#
}
#>
return <#= SIGNIFICANT_DECIMALS #>; // Max nr of digits in decimal
}
}
}
Log 메서드 (IMO가 가장 좋은 방법)를 사용하고 싶지 않은 경우이 작업이 수행됩니다. ToString ()을 사용 하여이 작업을 수행 할 수있는 가장 명확한 방법입니다.
Math.Abs(val).ToString("f0", CultureInfo.InvariantCulture).Length
또는 0.123M
한 자리 숫자로 계산하지면 다음을 수행하십시오 .
Math.Abs(val).ToString("#", CultureInfo.InvariantCulture).Length
사용자 지정 형식으로 ToString 함수를 사용할 수 있습니다.
Decimal value = 467.45m;
int count = Math.Abs(value).ToString("#", System.Globalization.CultureInfo.InvariantCulture).Length;
는 경우 #
에만 문자 전과를.
System.Globalization.CultureInfo.InvariantCulture
이 지역 옵션에서 모든 형식화하는 것을 보장합니다.
그래서, 나는 전에 이것을 실행하고 다음 코드로 해결했습니다.
SqlDecimal d = new SqlDecimal(467.45M);
int digits = d.Precision - d.Scale;
SqlDecimal
System.Data.SqlTypes
네임 스페이스의 일부 입니다 . "정밀도"는 총 유효 자릿수이고 "스케일"은 소수점 뒤의 자릿수입니다.
이제이 경로로가는 것에 대한 한 가지 반대 SqlDecimal
는 SQL Server 특정 코드의 일부라는 것을 알고 있습니다. 타당한 점이지만 .NET 프레임 워크 자체의 일부이고 버전 1.1 이상 주변 코드가 무엇을하든 계속 적용 가능할 것입니다. .
나는 디 컴파일러 ( 이 경우 는 JetBrains의 dotPeek) 로 후드 아래를 살펴보면서 정밀도와 스케일을 계산하는 코드를 쉽게 추출하고 SqlDecimal
. 단계별로 계산하는 코드는 매우 간단하지만 계산하는 방법은 사소한 것이 아니 나라면 SqlDecimal
.
이 대답은 Calculate System. Decimal Precision and Scale 에서 거의 비롯 질문에 약간 변경되었습니다.
class Program
{
static void Main()
{
decimal dec = 467.45m;
Console.WriteLine(dec.GetNumberOfDigitsBeforeDecimalPlace());
}
}
public static class DecimalEx
{
public static int GetNumberOfDigitsBeforeDecimalPlace(this decimal dec)
{
var x = new System.Data.SqlTypes.SqlDecimal(dec);
return x.Precision - x.Scale;
}
}
또한 SqlDecimal 클래스를 사용하지 않고 수행 한 질문에 대한 Jon Skeet의 답변을 확인하십시오.
var sep = Convert.ToChar(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
var count = d.ToString().TakeWhile(c => c != sep).Count();
이를 수행하는 수학적 방법 (아마도 가장 빠른 방법) 은이 숫자의 절대 값에 대해 밑이 10 인 logarytm을 구하여 반올림하는 것입니다.
Math.Floor(Math.Log10(Math.Abs(val)) + 1);
다른 모든 답변은 TLDR입니다. 나는 이것을 PHP로 썼고 수학은 같을 것입니다. (C #을 알았다면 그 언어로 작성했을 것입니다.)
$input=21689584.999;
$input=abs($input);
$exp=0;
do{
$test=pow(10,$exp);
if($test > $input){
$digits=$exp;
}
if($test == $input){
$digits=$exp+1;
}
$exp++;
}while(!$digits);
if($input < 1){$digits=0;}
echo $digits;
더 나은 방법이 있을지 의심하지 않지만 $ .02를 표현했습니다.
편집하다 :
나는 내 의견에서 한 코드를 PHP로 변환했지만 int 변환을 제거했습니다.
function digitCount($input){
$digits=0;
$input=abs($input);
while ($input >= 1) {
$digits++;
$input=$input/10;
//echo $input."<br>";
}
return $digits;
}
$big=(float)(PHP_INT_MAX * 1.1);
echo digitCount($big);
모듈로를 사용하십시오. 저는 C # 프로그래머가 최선을 다하고 있습니다.
double i = 1;
int numberOfDecimals = 0;
while (varDouble % i != varDouble)
{
numberOfDecimals++;
i*=10;
}
return numberOfDecimals;
이것이 자바 솔루션이 될 것입니다.
public class test {
public static void main(String args[]) {
float f = 1.123f;
int a = (int) f;
int digits = 0;
while (a > 0) {
digits++;
a=a/10;
}
System.out.println("No Of digits before decimal="+digits);
}
}
0 또는 0 부족을 1 숫자로 취급하면 괜찮습니다. 0이 0이 0을 반환하거나 0이 부족하여 0을 반환 할 추가하기가 너무 어렵지 않은 몇 가지 예외적 인 경우가 있습니다. 또한 음수를 처리해야 할 절대 값이어야합니다. 해당 테스트 케이스도 추가했습니다.
const decimal d = 123.45m;
const decimal d1 = 0.123m;
const decimal d2 = .567m;
const decimal d3 = .333m;
const decimal d4 = -123.45m;
NumberFormatInfo currentProvider = NumberFormatInfo.InvariantInfo;
var newProvider = (NumberFormatInfo) currentProvider.Clone();
newProvider.NumberDecimalDigits = 0;
string number = d.ToString("N", newProvider); //returns 123 = .Length = 3
string number1 = d1.ToString("N", newProvider); //returns 0 = .Length = 1
string number2 = d2.ToString("N", newProvider); //returns 1 = .Length = 1
string number3 = d3.ToString("N", newProvider); //returns 0 = .Length = 1
string number4 = Math.Abs(d4).ToString("N", newProvider); //returns 123 = .Length = 3
작동하지 않는 테스트 케이스를 찾으면 알려주세요. 제공된 테스트 케이스에 대해 3,0,0,0,3을 반환해야합니다.
public static int NumbersInFrontOfDecimal(decimal input)
{
NumberFormatInfo currentProvider = NumberFormatInfo.InvariantInfo;
var newProvider = (NumberFormatInfo)currentProvider.Clone();
newProvider.NumberDecimalDigits = 0;
var absInput = Math.Abs(input);
var numbers = absInput.ToString("N", newProvider);
//Handle Zero and < 1
if (numbers.Length == 1 && input < 1.0m)
{
return 0;
}
return numbers.Length;
}
다음은 Gray의 답변에서 영감을 얻은 최적화 된 코드 버전입니다.
static int GetNumOfDigits(decimal dTest)
{
int nAnswer = 0;
dTest = Math.Abs(dTest);
//For loop version
for (nAnswer = 0; nAnswer < 29 && dTest > 1; ++nAnswer)
{
dTest *= 0.1M;
}
//While loop version
//while (dTest > 1)
//{
// nAnswer++;
// dTest *= 0.1M;
//}
return (nAnswer);
}
이 함수 내에서 Math.Abs를 호출하지 않으려면 GetNumOfDigits를 호출하기 전에 매개 변수의 함수 외부에서이를 사용해야합니다.
나는이 시점에 도달하는 데 도움이되었지만 내 대답의 혼란을 줄이기 위해 다른 코드를 제거하기로 결정했습니다.
개선이 필요한 경우 알려 주시면 업데이트하겠습니다 :).
정확하고 문화적으로 불가지론적인 답변을 얻기 위해 다음을 수행합니다.
- 사용
System.Numerics.BigInteger
누구의 생성자는 소수점을 허용하지 않는 것 반올림 오류를 생성 할 수 있습니다. BigInteger.Abs()
기호를 제거하는 데 사용 합니다.BigInteger.ToString()
발생할 수있는 구분 기호를 억제하려면 "#"형식과 함께 사용하십시오 .
암호
decimal num = 123213123.123123M;
int length = BigInteger.Abs((BigInteger)num).ToString("#").Length;
숫자를 반올림 한 다음 새 숫자의 길이를 구하면됩니다. 다음과 같이 할 수 있습니다.
var number = 476.43;
var newNumber = Math.round(number);
//get the length of the rounded number, and subtract 1 if the
//number is negative (remove the negative sign from the count)
int digits = newNumber.ToString().Length - (number < 0 ? 1 : 0);
다른 솔루션은 숫자가 너무 크면 숫자를 잃게됩니다.
public int Digits(Decimal i)
{
NumberFormatInfo format = CultureInfo.CurrentCulture.NumberFormat;
var str = Math.Abs(i).ToString().Replace(format.NumberGroupSeparator, "");
var index = str.IndexOf(format.NumberDecimalSeparator);
var digits = index == -1 ? str.Length : index;
}
연산:
|decimal|
문자열로 변환 합니다."."
소수에 있으면 그 전에 잘라 내고 그렇지 않으면 정수를 고려하십시오.- 문자열 길이를 반환합니다.
예:
3.14 --> 3.14 --> "3.14" --> "3.14".Substring(0,1) --> "3".Length --> 1
-1024 --> 1024 --> "1024" --> IndexOf(".") = -1 --> "1024" --> 4
암호:
static int getNumOfDigits (decimal num)
{
string d = Math.Abs(num).ToString();
if (d.IndexOf(".") > -1)
{
d = d.Substring(0, d.IndexOf("."));
}
return d.Length;
}
나는 이것을 테스트하지 않았지만 간단하게 유지하고 다음을 수행합니다.
decimal value = 467.45;
string str = Convert.toString(value); // convert your decimal type to a string
string[] splitStr = str.split('.'); // split it into an array (use comma separator assuming you know your cultural context)
Console.WriteLine(splitStr[0].Count); // get the first element. You can also get the number of figures after the point by indexing the next value in the array.
이것은 음수를 처리하지 않습니다. 그것들에 관심이 있다면 절대 가치를 고려하십시오. 또한 소수 자리 앞의 0을 계산하지 않으려면 간단한 if 문을 사용하여 확인할 수 있습니다.
간단하다 :
string value = "467.45";
int count = value.split('.')[0] == "0" ? 0 : value.split('.')[0].ToString().Replace("-","").Count();
참고 URL : https://stackoverflow.com/questions/21546793/get-number-of-digits-before-decimal-point
'ProgramingTip' 카테고리의 다른 글
오류 : 기호 변수 abc_ic_ab_back_mtrl_am_alpha를 사용할 수 없습니다. (0) | 2020.11.22 |
---|---|
'this'포인터는 컴퓨터 메모리에 어디에 저장합니까? (0) | 2020.11.22 |
함수가 함수에 대한 포인터를 반환하는 방법은 무엇입니까? (0) | 2020.11.22 |
DataContractSerializer를 사용하여 생성 화하지만 역화 할 수 없음 (0) | 2020.11.22 |
If, Else, For, Foreach 등의 절을 접는 방법은 무엇입니까? (0) | 2020.11.22 |