Czy w C # jest operator wykładnika?

194

Na przykład, czy istnieje operator, który sobie z tym poradzi?

float Result, Number1, Number2;

Number1 = 2;
Number2 = 2;

Result = Number1 (operator) Number2;

W przeszłości ^operator pełnił funkcję operatora wykładniczego w innych językach, ale w języku C # jest operatorem nieco mądrzejszym.

Czy muszę pisać pętlę lub zawierać inną przestrzeń nazw do obsługi operacji wykładniczych? Jeśli tak, w jaki sposób obsługiwać operacje wykładnicze przy użyciu liczb całkowitych?

Charlie
źródło
7
Nie ma go w języku C #, ale wiele języków używa **jako operatora potęgowania potęgi.
Mark Rushakoff
przyjechałem tutaj, ponieważ byłem podekscytowany, że 10 ^ 7 zapisanych w długim / Int64 dawało mi „13”. Próbowałem również 1E7, ale to dało mi błąd typu. Ponieważ nie widziałem błędu typu / błędu składni niedozwolonego operatora, założyłem, że moja 10 ^ 7 działa ...
mpag
1
@mpag ^ jest wyłącznym operatorem lub operatorem, więc 10 ^ 7 = 1010b XOR 0111b = 1101b = 13.
Ian Brockbank

Odpowiedzi:

228

Język C # nie ma operatora mocy . Jednak .NET Framework oferuje metodę Math.Pow :

Zwraca określoną liczbę podniesioną do określonej mocy.

Twój przykład wyglądałby tak:

float Result, Number1, Number2;

Number1 = 2;
Number2 = 2;

Result = Math.Pow(Number1, Number2);
dtb
źródło
1
Pamiętaj o ograniczeniu wydajności, jeśli używasz Math.Pow do kwadratu: stackoverflow.com/questions/936541/...
Justas
4
@Justas Właśnie testowałem to w .NET Core 2.1 i Math.Pow jest teraz szybszy niż sugerowana alternatywna implementacja.
bytedev
50

Natknąłem się na ten post, próbując użyć notacji naukowej w moim kodzie, użyłem

4.95*Math.Pow(10,-10);

Ale potem odkryłem, że możesz to zrobić

4.95E-10;

Pomyślałem, że dodam to dla każdego w podobnej sytuacji, w jakiej byłem.

Generał Gray
źródło
34

W witrynie MSDN znajduje się post na blogu o tym, dlaczego operator wykładnika NIE istnieje od zespołu C #.

Możliwe byłoby dodanie operatora języka do języka, ale wykonanie tej operacji jest dość rzadką rzeczą w większości programów, a dodanie operatora, gdy wywołanie Math.Pow () jest proste, nie wydaje się uzasadnione .


Zapytałeś:

Czy muszę pisać pętlę lub zawierać inną przestrzeń nazw do obsługi operacji wykładniczych? Jeśli tak, w jaki sposób obsługiwać operacje wykładnicze przy użyciu liczb całkowitych?

Math.Pow obsługuje podwójne parametry, więc nie musisz pisać własnych.

Brian R. Bondy
źródło
24
Rozumiem ten argument, ale poprawnym powodem jest to, że Math.Pow () nie może być użyty do ustawiania wartości stałych, co sprawia, że ​​wykładniki nie nadają się do użycia dla wszystkich stałych.
jsmars,
1
Operator mocy byłby wygodny w przypadku przeciążenia operatora, dla mnie Math.Pow () nie uzasadnia faktu, że nie tworzy operatora wykładnika, ponieważ Math.Pow () nie jest operatorem, a zatem nie ma takich samych zastosowań jak operator ._ .
Alexandre Daubricourt,
8

Brak operatora wykładniczego dla języka C # był dla nas dużą uciążliwością, gdy szukaliśmy nowego języka do konwersji naszego oprogramowania obliczeniowego z dobrej starej wersji vb6.

Cieszę się, że wybraliśmy C #, ale wciąż denerwuje mnie, gdy piszę złożone równanie, w tym wykładniki. Metoda Math.Pow () sprawia, że ​​równania są dość trudne do odczytania przez IMO.

Naszym rozwiązaniem było stworzenie specjalnej klasy DoubleX, w której przesłonimy operator ^ (patrz poniżej)

Działa to dość dobrze, o ile deklarujesz przynajmniej jedną ze zmiennych jako DoubleX:

DoubleX a = 2;
DoubleX b = 3;

Console.WriteLine($"a = {a}, b = {b}, a^b = {a ^ b}");

lub użyj jawnego konwertera na standardowe podwójne:

double c = 2;
double d = 3;

Console.WriteLine($"c = {c}, d = {d}, c^d = {c ^ (DoubleX)d}");     // Need explicit converter

Jednym z problemów związanych z tą metodą jest to, że wykładnik obliczany jest w niewłaściwej kolejności w porównaniu do innych operatorów. Można tego uniknąć, zawsze umieszczając dodatkową () wokół operacji, co ponownie utrudnia odczytanie równań:

DoubleX a = 2;
DoubleX b = 3;

Console.WriteLine($"a = {a}, b = {b}, 3+a^b = {3 + a ^ b}");        // Wrong result
Console.WriteLine($"a = {a}, b = {b}, 3+a^b = {3 + (a ^ b)}");      // Correct result

Mam nadzieję, że może to pomóc innym, którzy używają wielu złożonych równań w swoim kodzie, a może ktoś nawet ma pomysł, jak ulepszyć tę metodę ?! :-)

Klasa DoubleX:

using System;

namespace ExponentialOperator
{
    /// <summary>
    /// Double class that uses ^ as exponential operator
    /// </summary>
    public class DoubleX
    {
        #region ---------------- Fields ----------------

        private readonly double _value;

        #endregion ------------- Fields ----------------

        #region -------------- Properties --------------

        public double Value
        {
            get { return _value; }
        }

        #endregion ----------- Properties --------------

        #region ------------- Constructors -------------

        public DoubleX(double value)
        {
            _value = value;
        }

        public DoubleX(int value)
        {
            _value = Convert.ToDouble(value);
        }

        #endregion ---------- Constructors -------------

        #region --------------- Methods ----------------

        public override string ToString()
        {
            return _value.ToString();
        }

        #endregion ------------ Methods ----------------

        #region -------------- Operators ---------------

        // Change the ^ operator to be used for exponents.

        public static DoubleX operator ^(DoubleX value, DoubleX exponent)
        {
            return Math.Pow(value, exponent);
        }

        public static DoubleX operator ^(DoubleX value, double exponent)
        {
            return Math.Pow(value, exponent);
        }

        public static DoubleX operator ^(double value, DoubleX exponent)
        {
            return Math.Pow(value, exponent);
        }

        public static DoubleX operator ^(DoubleX value, int exponent)
        {
            return Math.Pow(value, exponent);
        }

        #endregion ----------- Operators ---------------

        #region -------------- Converters --------------

        // Allow implicit convertion

        public static implicit operator DoubleX(double value)
        {
            return new DoubleX(value);
        }

        public static implicit operator DoubleX(int value)
        {
            return new DoubleX(value);
        }

        public static implicit operator Double(DoubleX value)
        {
            return value._value;
        }

        #endregion ----------- Converters --------------
    }
}
Petter
źródło
2

Dziwię się, że nikt o tym nie wspominał, ale w przypadku prostego (i prawdopodobnie najczęściej spotykanego) przypadku kwadratu wystarczy pomnożyć sam.

float Result, Number1;

Result = Number1 * Number1;
Gumowa kaczuszka
źródło
4
to nie rozmnażanie, jego moc.
Henry,
Tak @Henry i jak wspomnieli inni, operator nie istnieje. Właśnie Math.Pow. Właśnie oferowałem oczywiste rozwiązanie najczęstszego przypadku.
RubberDuck,
4
Również znacznie szybszy niżMath.Pow(Number1, 2)
lamont
2

Ponieważ nikt jeszcze nie napisał funkcji, aby to zrobić z dwiema liczbami całkowitymi, oto jeden sposób:

private long CalculatePower(int number, int powerOf)
{
    for (int i = powerOf; i > 1; i--)
        number *= number;
    return number;
}
CalculatePower(5, 3); // 125
CalculatePower(8, 4); // 4096
CalculatePower(6, 2); // 36

Alternatywnie w VB.NET:

Private Function CalculatePower(number As Integer, powerOf As Integer) As Long
    For i As Integer = powerOf To 2 Step -1
        number *= number
    Next
    Return number
End Function
CalculatePower(5, 3) ' 125
CalculatePower(8, 4) ' 4096
CalculatePower(6, 2) ' 36
Nathangrad
źródło
Czy ktoś może wyjaśnić opinię negatywną? Przetestowałem ten kod i ty też możesz na ideone.com/o9mmAo (C #) i ideone.com/vnaczj (VB.NET) - wygląda na to, że działa doskonale.
Nathangrad,
8
Ponieważ istnieją Math.Pow, więc twój kod jest nieistotny
Thaina,
1
Math.Pow () jest jednak powolny i będzie znacznie szybszy, o ile PowerOf jest stosunkowo mały.
lamont
3
@Nathangrad Reinventing (kwadratowego) koła jest w dużej mierze uważany za anty-wzór. FYI: exceptionnotfound.net/...
bytedev
Są też szybsze sposoby na wdrożenie własnej metody zasilania. Zobacz: en.wikipedia.org/wiki/Exponentiation_by_squaring
Jesse Chisholm
0

Dobra byłaby funkcja mocy

    public long Power(int number, int power) {
        if (number == 0) return 0;
        long t = number;
        int e = power;
        int result = 1;
        for(i=0; i<sizeof(int); i++) {
            if (e & 1 == 1) result *= t;
            e >>= 1;
            if (e==0) break;
            t = t * t;
        }
    }

Funkcja `Math.Pow` wykorzystuje funkcję zasilania procesora i jest znacznie bardziej wydajna.

Warny
źródło
0

Za to, co warto, tęsknię za operatorem ^ podczas podnoszenia potęgi 2 w celu zdefiniowania stałej binarnej. Nie można tam użyć Math.Pow (), ale działa przesunięcie liczby całkowitej bez znaku 1 w lewo o wartość wykładnika. Kiedy musiałem zdefiniować stałą (2 ^ 24) -1:

public static int Phase_count = 24;
public static uint PatternDecimal_Max = ((uint)1 << Phase_count) - 1;

Pamiętaj, że typami muszą być (uint) << (int).

Graham Gunderson
źródło