Uzyskaj część dziesiętną z podwójnego


85

Chcę otrzymać liczbę po kropce dziesiętnej w postaci liczby całkowitej. Na przykład tylko 05 od 1,05 lub od 2,50 tylko 50, a nie 0,50


15
2,50 to tylko 2,5. Zakładam, że mówisz o strunach.
Tim Schmelter,

3
Czy zawsze zwracasz pierwsze dwie cyfry po przecinku? Czy wejście decimal, float, string, ...?
Greg

3
Przykładowe zastosowania to duża droga do uzyskania wartościowych odpowiedzi na następny raz.
tmesser

tak tylko do cyfr, wejście jest dziesiętne
użytkownik1095549

4
Zespół programistów C # powinien być zawstydzony (i podjąć działania), że ta bardzo powszechna operacja nie ma jednej funkcji Math.function, takiej jak Math.DecimalPart (double x) lub coś w tym rodzaju. Jest o wiele za dużo „czy próbowałeś tego, czy myślałeś o tym” na coś, co wielu z nas musi często robić.
filologon

Odpowiedzi:


-21

Zaktualizowana odpowiedź

Tutaj podaję 3 podejścia do tego samego.

[1] Rozwiązanie matematyczne przy użyciu Math.Truncate

 var float_number = 12.345;
 var result = float_number - Math.Truncate(float_number);

// wejście: 1.05
// wyjście: "0.050000000000000044"

// wejście: 10.2
// wyjście: 0.19999999999999929

Jeśli nie jest to oczekiwany wynik, musisz zmienić wynik na żądaną formę (ale możesz ponownie wykonać pewne operacje na ciągach).

[2] używając mnożnika [który wynosi 10 do potęgi N (np. 10² lub 10³), gdzie N to liczba miejsc dziesiętnych]

       // multiplier is " 10 to the power of 'N'" where 'N' is the number 
       // of decimal places
       int multiplier = 1000;  
       double double_value = 12.345;
       int double_result = (int)((double_value - (int)double_value) * multiplier);

// wypisz 345

Jeśli liczba miejsc dziesiętnych nie zostanie ustalona, ​​to podejście może powodować problemy.

[3] używając „Wyrażeń regularnych (REGEX)”

powinniśmy być bardzo ostrożni podczas pisania rozwiązań z użyciem stringów. Nie byłoby to preferowane z wyjątkiem niektórych przypadków.

Jeśli zamierzasz wykonywać operacje na łańcuchach z miejscami dziesiętnymi, byłoby to preferowane

    string input_decimal_number = "1.50";
    var regex = new System.Text.RegularExpressions.Regex("(?<=[\\.])[0-9]+");
    if (regex.IsMatch(input_decimal_number))
    {
        string decimal_places = regex.Match(input_decimal_number).Value;
    }

// wejście: "1.05"
// wyjście: "05"

// wejście: „2,50”
// wyjście: „50”

// wejście: „0,0550”
// wyjście: „0550”

więcej informacji na temat Regex można znaleźć na stronie http://www.regexr.com/


Uważaj z ToString (), ponieważ nie zwróci części dziesiętnych dla liczb całkowitych, to znaczy, jeśli MyValue wynosi 3, MyValue.ToString () zwróci „3”, więc zostanie rzucony Split ('.') [1]. Rozważ jawne określenie wymaganej liczby miejsc dziesiętnych: MyValue.ToString („F2”). Split („.”) [1]
Alex Beynenson

7
To rozwiązanie jest mniej więcej dwa rzędy wielkości wolniejsze niż jakiekolwiek inne rozwiązanie na tej stronie i cztery rzędy wielkości wolniejsze niż moja własna odpowiedź.
tmesser

1
To rozwiązanie jest specyficzne dla kultury. Na przykład w językach rosyjskim i angielsko-amerykańskim istnieje inny separator dziesiętny (odpowiednio przecinek i kropka). Więc ten kod nie powiedzie się w ustawieniach innych kultur.
Yury Schkatula

2
To rozwiązanie dzieli się na ., który nie zawsze jest separatorem dziesiętnym (tj. W Europie separatorem dziesiętnym jest ,). Musisz CultureInfo.Invariantcoś dodać, żeby było międzynarodowe. Chociaż łatwiej jest po prostu użyć x - Math.Truncate(x)i zrobić magię na tym wyniku.
Abel

3
@Kiquenet Ponieważ jest to siódma wersja. To była oryginalna odpowiedź: stackoverflow.com/revisions/19374418/1
Manfred Radlwimmer

199

najlepszy z najlepszych sposobów to:

var floatNumber = 12.5523;

var x = floatNumber - Math.Truncate(floatNumber);

wynik, który możesz konwertować w dowolny sposób


10
To powinna być akceptowana odpowiedź, matematyczne rozwiązanie pytania matematycznego, bez tego żmudnego
grzebania

20
Myślę, że to rozwiązanie ma „problem”. Jeśli floatNumber ma wartość „10,2”, zmienna x będzie miała wartość podobną do „0,19999999999999929”. Nawet jeśli działa to zgodnie z oczekiwaniami, wynikiem będzie „0,2”, a nie „2”.
Dherik,

4
@Dherik Float i Double zawsze mają małe błędy przy odejmowaniu w ostatnich kilku miejscach po przecinku. Nie powinieneś uważać ich za znaczące. Jeśli faktycznie potrzebujesz takiej precyzji, powinieneś użyć typu dziesiętnego. Jeśli nie możesz przełączyć się na Decimal (lub po prostu nie chcesz), powinieneś w jakiś sposób śledzić oczekiwaną dokładność i uwzględnić to w operacjach porównania. Zwykle używam 4 miejsc po przecinku, ale mogą być wyjątki od tego.
filologon

Z msdn.microsoft.com/en-us/library/… : „Ponieważ niektóre liczby nie mogą być reprezentowane dokładnie jako ułamkowe wartości binarne, liczby zmiennoprzecinkowe mogą jedynie przybliżać liczby rzeczywiste”
filologon

1
Komentarz końcowy: Zamiarem autora biblioteki Math w takich sytuacjach było użycie Math.Truncate. Odpowiedź @Matterai powinna być zaakceptowana.
filologon

81
var decPlaces = (int)(((decimal)number % 1) * 100);

Zakłada to, że Twój numer ma tylko dwa miejsca po przecinku.


1
(318.40d % 1) * 100wyjścia 39.9999999999977, możesz użyć rzutowania, aby obejść błąd zaokrąglania:var decPlaces = (int)(((decimal)number % 1) * 100);
orad

@orad Dobre wezwanie - liczby zmiennoprzecinkowe zawsze mają te małe niedokładności, więc rzutowanie jest dość rozsądne, aby zapewnić spójne zachowanie. Zaktualizuję swoją odpowiedź, chociaż Matterai jest jeszcze bardziej poprawna technicznie.
tmesser

27

Istnieje bardziej przejrzyste i szybsze rozwiązanie niż podejście „Math.Truncate”:

double frac = value % 1;

7
uwaga: dla wartości ujemnych jest ujemny : -12,34% 1 => -0,33999999999999986
Alex Poca

16

Rozwiązanie bez problemu z zaokrągleniem:

double number = 10.20;
var first2DecimalPlaces = (int)(((decimal)number % 1) * 100);
Console.Write("{0:00}", first2DecimalPlaces);

Wyjścia: 20

Zauważ, że gdybyśmy nie rzutowali na liczbę dziesiętną, to wyświetli się 19.

Również:

  • dla 318.40wyjść: 40(zamiast 39)
  • dla 47.612345wyjść: 61(zamiast 612345)
  • dla 3.01wyjść: 01(zamiast 1)

Jeśli pracujesz z numerami finansowych, na przykład, jeśli w tym przypadku staramy się uzyskać centów część kwoty transakcji, należy zawsze używać decimaltypu danych.

Aktualizacja:

Poniższe działania będą również działać, jeśli przetwarzają go jako ciąg (opierając się na odpowiedzi @ SearchForKnowledge).

10.2d.ToString("0.00", CultureInfo.InvariantCulture).Split('.')[1]

Następnie możesz użyć, Int32.Parseaby przekonwertować go na int.


1
Kciuki w górę dla modów
Ivandro Jao

Użyłem tego ... 10.2d.ToString ("0,00", CultureInfo.InvariantCulture) .Split ('.') [1]
Ziggler

10

Better Way -

        double value = 10.567;
        int result = (int)((value - (int)value) * 100);
        Console.WriteLine(result);

Wynik -

56

2
Nie testowałem, ale cierpi z powodu niedokładności pływaka, nie?
mafu

Na 10.20to wyjdzie 19. Zobacz moją odpowiedź.
orad

9

Najprostszym wariantem jest prawdopodobnie Math.truncate ()

double value = 1.761
double decPart = value - Math.truncate(value)

2

Myślę, że ten wątek się starzeje, ale nie mogę uwierzyć, że nikt nie wspomniał o Math.Floor

//will always be .02 cents
(10.02m - System.Math.Floor(10.02m))

Dla super leniwych:double fract(double x) { return x - System.Math.Floor(x); }
Felipe Gutierrez

1
var result = number.ToString().Split(System.Globalization.NumberDecimalSeparator)[2]

Zwraca to jako ciąg (ale zawsze można to rzutować z powrotem na liczbę int) i zakłada, że ​​liczba ma znak „.” gdzieś.


1
int last2digits = num - (int) ((double) (num /  100) * 100);

Pytanie brzmi, aby uzyskać pierwsze 2 cyfry dziesiętne. Dla liczby 318.401567dTwoje rozwiązanie wyświetla się 0.401567tam, gdzie 40jest oczekiwane.
orad

0
    public static string FractionPart(this double instance)
    {
        var result = string.Empty;
        var ic = CultureInfo.InvariantCulture;
        var splits = instance.ToString(ic).Split(new[] { ic.NumberFormat.NumberDecimalSeparator }, StringSplitOptions.RemoveEmptyEntries);
        if (splits.Count() > 1)
        {
            result = splits[1];
        }
        return result;
    }

0

Oto metoda rozszerzenia, którą napisałem dla podobnej sytuacji. Moja aplikacja otrzymałaby liczby w formacie 2,3 lub 3,11, gdzie składnik całkowity liczby reprezentowanej przez lata, a składnik ułamkowy reprezentowałby miesiące.

// Sample Usage
int years, months;
double test1 = 2.11;
test1.Split(out years, out months);
// years = 2 and months = 11

public static class DoubleExtensions
{
    public static void Split(this double number, out int years, out int months)
    {
        years = Convert.ToInt32(Math.Truncate(number));

        double tempMonths = Math.Round(number - years, 2);
        while ((tempMonths - Math.Floor(tempMonths)) > 0 && tempMonths != 0) tempMonths *= 10;
        months = Convert.ToInt32(tempMonths);
    }
}

0

Może to być kosztowne, ale powinno działać.

double yourDouble = 1.05;
string stringForm = yourDouble.ToString();
int dotPosition = stringForm.IndexOf(".");
decimal decimalPart = Decimal.Parse("0" + stringForm.Substring(dotPosition));

Console.WriteLine(decimalPart); // 0.05

0
 string input = "0.55";
    var regex1 = new System.Text.RegularExpressions.Regex("(?<=[\\.])[0-9]+");
    if (regex1.IsMatch(input))
    {
        string dp= regex1.Match(input ).Value;
    }

1
Byłoby wspaniale, gdybyś mógł dodać opis, w jaki sposób wyrażenie regularne pomaga rozwiązać problem
Cleptus

-1

Możesz usunąć kropkę .z podwójnej liczby, którą próbujesz uzyskać ułamki dziesiętne, używając Remove()funkcji po konwersji podwójnej na ciąg, aby móc wykonać na niej wymagane operacje

Rozważ podwójną _Doublewartość 0.66781, poniższy kod pokaże tylko liczby po kropce, .które są66781

double _Double = 0.66781; //Declare a new double with a value of 0.66781
string _Decimals = _Double.ToString().Remove(0, _Double.ToString().IndexOf(".") + 1); //Remove everything starting with index 0 and ending at the index of ([the dot .] + 1) 

Inne rozwiązanie

Możesz również użyć klasy, Pathktóra wykonuje operacje na wystąpieniach ciągów w sposób wieloplatformowy

double _Double = 0.66781; //Declare a new double with a value of 0.66781
string Output = Path.GetExtension(D.ToString()).Replace(".",""); //Get (the dot and the content after the last dot available and replace the dot with nothing) as a new string object Output
//Do something

-2

Użyj wyrażenia regularnego: Regex.Match("\.(?\d+)")ktoś popraw mnie, jeśli się mylę


Niezbyt popularne z, Regex.Matchale otrzymałem następujący błąd podczas próby uzyskania wartości dziesiętnejArgumentException was unhandled: parsing "\.(?\d+)" - Unrecognized grouping construct.
Picrofo Software

-2

To bardzo proste

       float moveWater =  Mathf.PingPong(theTime * speed, 100) * .015f;
       int    m = (int)(moveWater);
       float decimalPart= moveWater -m ;

       Debug.Log(decimalPart);

-2

Dlaczego nie używać int y = value.Split('.')[1];?

Split()Funkcja dzieli wartość w osobne i 1wysyłającym 2. wartości po.


To zadziała:Int32.Parse((12.05123d.ToString("0.00").Split('.')[1]))
orad

Ponieważ rzucasz go na strunę, aby dokonać manipulacji na strunie. Myślę, że nie zdajesz sobie sprawy, jak powolne i marnotrawne jest to.
dmarra
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.