มีตัวดำเนินการเลขชี้กำลังใน C # หรือไม่


194

ตัวอย่างเช่นมีโอเปอเรเตอร์ที่จะจัดการกับสิ่งนี้หรือไม่?

float Result, Number1, Number2;

Number1 = 2;
Number2 = 2;

Result = Number1 (operator) Number2;

ในอดีตที่ผ่านมา^ผู้ประกอบการได้ทำหน้าที่เป็นผู้ดำเนินการชี้แจงในภาษาอื่น ๆ แต่ใน C # มันเป็นผู้ประกอบการบิตที่ชาญฉลาด

ฉันต้องเขียนลูปหรือรวมเนมสเปซอื่นเพื่อจัดการการดำเนินการเอ็กซ์โปเนนเชียลหรือไม่? ถ้าเป็นเช่นนั้นฉันจะจัดการการดำเนินการเอ็กซ์โปเนนเชียลโดยใช้ที่ไม่ใช่จำนวนเต็มได้อย่างไร


7
มันไม่ได้อยู่ใน C # แต่หลายภาษาใช้**เป็นตัวดำเนินการการยกกำลังแบบมัด
Mark Rushakoff

มาที่นี่เพราะฉันรู้สึกสับสนที่ 10 ^ 7 เก็บไว้ในที่นาน / Int64 ให้ฉัน "13. " ฉันลอง 1E7 ด้วยเช่นกัน แต่นั่นทำให้ฉันมีข้อผิดพลาดประเภท เนื่องจากฉันไม่เห็นข้อผิดพลาดประเภท / ข้อผิดพลาดทางไวยากรณ์ของผู้ดำเนินการที่ผิดกฎหมายฉันจึงสันนิษฐานว่า 10 ^ 7 ของฉันทำงานอยู่ ...
mpag

1
@mpag ^ เป็นเอกสิทธิ์หรือตัวดำเนินการดังนั้น 10 ^ 7 = 1010b XOR 0111b = 1101b = 13
Ian Brockbank

คำตอบ:


228

ภาษา C # ไม่ได้มีผู้ประกอบการพลังงาน อย่างไรก็ตาม. NET Framework เสนอวิธีMath.Pow :

ส่งคืนตัวเลขที่ระบุที่ยกกำลังไฟที่ระบุ

ดังนั้นตัวอย่างของคุณจะเป็นดังนี้:

float Result, Number1, Number2;

Number1 = 2;
Number2 = 2;

Result = Math.Pow(Number1, Number2);

1
โปรดทราบว่าการลงโทษประสิทธิภาพหากใช้ Math.Pow สำหรับการยกกำลังสอง: stackoverflow.com/questions/936541/…
Justas

4
@ Justas ฉันเพิ่งทดสอบว่าใน. NET Core 2.1 และ Math.Pow ตอนนี้เร็วกว่าการใช้ทางเลือกที่แนะนำ
bytedev

50

ฉันสะดุดกับโพสต์นี้ที่ต้องการใช้สัญกรณ์ทางวิทยาศาสตร์ในรหัสของฉันฉันใช้

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

แต่หลังจากนั้นฉันก็พบว่าคุณสามารถทำได้

4.95E-10;

แค่คิดว่าฉันจะเพิ่มสิ่งนี้สำหรับทุกคนในสถานการณ์ที่คล้ายกันที่ฉันเป็น


34

มีการโพสต์บล็อกบน MSDN เกี่ยวกับสาเหตุที่ผู้ดำเนินการเลขชี้กำลังไม่มีอยู่จากทีม C #

อาจเป็นไปได้ที่จะเพิ่มตัวดำเนินการพลังงานให้กับภาษา แต่การดำเนินการนี้เป็นสิ่งที่ค่อนข้างหายากที่ต้องทำในโปรแกรมส่วนใหญ่และดูเหมือนจะไม่เป็นธรรมที่จะเพิ่มตัวดำเนินการเมื่อเรียกMath.Pow () เป็นเรื่องง่าย


คุณถาม:

ฉันต้องเขียนลูปหรือรวมเนมสเปซอื่นเพื่อจัดการการดำเนินการเอ็กซ์โปเนนเชียลหรือไม่? ถ้าเป็นเช่นนั้นฉันจะจัดการการดำเนินการเอ็กซ์โปเนนเชียลโดยใช้ที่ไม่ใช่จำนวนเต็มได้อย่างไร

Math.Pow รองรับพารามิเตอร์สองค่าดังนั้นคุณไม่จำเป็นต้องเขียนของคุณเอง


24
ฉันเข้าใจการโต้แย้ง แต่เหตุผลที่ถูกต้องคือ Math.Pow () ไม่สามารถใช้เพื่อตั้งค่า const ซึ่งทำให้ exponents ไม่สามารถใช้ได้กับค่าคงที่ทั้งหมด
jsmars

1
ตัวดำเนินการพลังงานจะสะดวกสำหรับตัวดำเนินการมากเกินไปสำหรับฉัน Math.Pow () ไม่ได้พิสูจน์ว่าการไม่สร้างตัวดำเนินการเลขชี้กำลังเนื่องจาก Math.Pow () ไม่ได้เป็นตัวดำเนินการดังนั้นจึงไม่มีประเพณีเดียวกันกับตัวดำเนินการ _ .
Alexandre Daubricourt

8

การขาดตัวดำเนินการเลขชี้กำลังสำหรับ C # นั้นเป็นเรื่องที่น่ารำคาญอย่างมากสำหรับเราเมื่อต้องการภาษาใหม่เพื่อแปลงซอฟต์แวร์การคำนวณของเราเป็นจาก ol 6 v6 ที่ดี

ฉันดีใจที่เราไปกับ C # แต่ก็ยังทำให้ฉันรำคาญเมื่อใดก็ตามที่ฉันเขียนสมการที่ซับซ้อนรวมถึงเลขชี้กำลัง วิธีการ Math.Pow () ทำให้สมการค่อนข้างยากที่จะอ่าน IMO

วิธีการแก้ปัญหาของเราคือการสร้างคลาส DoubleX พิเศษที่เราแทนที่ ^ -operator

วิธีนี้ใช้งานได้ดีตราบใดที่คุณประกาศตัวแปรอย่างน้อยหนึ่งตัวเป็น DoubleX:

DoubleX a = 2;
DoubleX b = 3;

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

หรือใช้ตัวแปลงที่ชัดเจนกับคู่มาตรฐาน:

double c = 2;
double d = 3;

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

ปัญหาอย่างหนึ่งของวิธีนี้แม้ว่าจะมีการคำนวณเลขชี้กำลังในลำดับที่ไม่ถูกต้องเมื่อเทียบกับตัวดำเนินการอื่น สิ่งนี้สามารถหลีกเลี่ยงได้โดยการใส่พิเศษ () รอบการดำเนินการซึ่งทำให้ยากต่อการอ่านสมการอีกครั้ง:

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

ฉันหวังว่านี่จะช่วยคนอื่น ๆ ที่ใช้สมการที่ซับซ้อนจำนวนมากในรหัสของพวกเขาและบางทีใครบางคนอาจมีความคิดว่าจะปรับปรุงวิธีนี้ได้อย่างไร! :-)

คลาส 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 --------------
    }
}

2

ฉันประหลาดใจที่ไม่มีใครพูดถึงเรื่องนี้ แต่สำหรับกรณีของการยกกำลังสองคุณอาจแค่คูณด้วยตัวของมันเอง

float Result, Number1;

Result = Number1 * Number1;

4
มันไม่ใช่การทวีคูณพลังของมัน
เฮนรี่

ใช่ @Henry และอย่างที่คนอื่น ๆ พูดถึงผู้ประกอบการไม่มีอยู่จริง Math.Powเพียงแค่ ฉันเพิ่งเสนอวิธีแก้ปัญหาที่ชัดเจนสำหรับกรณีที่พบบ่อยที่สุด
RubberDuck

4
ยังเร็วกว่ามากMath.Pow(Number1, 2)
lamont

2

เนื่องจากยังไม่มีใครเขียนฟังก์ชั่นนี้ด้วยจำนวนเต็มสองจำนวนนี่เป็นวิธีหนึ่ง:

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

อีกทางเลือกหนึ่งใน 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

มีใครช่วยอธิบายการโหวตได้บ้างไหม? ฉันได้ทดสอบโค้ดนี้แล้วและคุณก็สามารถทำได้ที่ideone.com/o9mmAo (C #) & ideone.com/vnaczj (VB.NET) - ดูเหมือนว่ามันจะทำงานได้อย่างสมบูรณ์แบบ
Nathangrad

8
เพราะมี Math.Pow ดังนั้นโค้ดของคุณจึงไม่เกี่ยวข้อง
Thaina

1
Math.Pow () ช้าและนี่จะเร็วขึ้นอย่างมากตราบใดที่ PowerOf มีขนาดเล็กพอสมควร
lamont

3
@ ณัฐกราดการบูรณะวงล้อ (สี่เหลี่ยม) นั้นถือว่าเป็นรูปแบบการต่อต้าน FYI: exceptionnotfound.net/…
bytedev

นอกจากนี้ยังเป็นวิธีที่เร็วกว่าในการใช้วิธีการใช้พลังงานของคุณเอง ดู: en.wikipedia.org/wiki/Exponentiation_by_squaring
Jesse Chisholm

0

ฟังก์ชั่นพลังงานที่ดีจะเป็น

    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;
        }
    }

ฟังก์ชั่น 'Math.Pow` ใช้ฟังก์ชั่นพลังงานโปรเซสเซอร์และมีประสิทธิภาพสูงขึ้น


0

สำหรับสิ่งที่คุ้มค่าฉันควรพลาดโอเปอเรเตอร์ ^ เมื่อยกกำลัง 2 เพื่อกำหนดค่าคงที่ไบนารี ไม่สามารถใช้ Math.Pow () ที่นั่นได้ แต่เปลี่ยน int ที่ไม่ได้ลงนามเป็น 1 ไปทางซ้ายโดยการทำงานของค่าเลขชี้กำลัง เมื่อฉันต้องการกำหนดค่าคงที่ (2 ^ 24) -1:

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

จำไว้ว่าประเภทต้องเป็น (uint) << (int)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.