490 lines · 16.2 KB · C#
RawDownload
//******************************************************************************************************//  ComplexNumber.cs - Gbtc////  Copyright © 2016, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may//  not use this file except in compliance with the License. You may obtain a copy of the License at:////      http://opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  04/14/2016 - Stephen C. Wills//       Generated original version of source code.////****************************************************************************************************** using System;using System.Data.SqlTypes;using System.Text;using System.Text.RegularExpressions;using Microsoft.SqlServer.Server; namespace GSF.Core.SqlClr{    /// <summary>    /// Defines a complex number type that can be used in a SQL Server database.    /// </summary>    [Serializable]    [SqlUserDefinedType(Format.Native, IsByteOrdered = true)]    public struct ComplexNumber : INullable    {        #region [ Members ]         // Fields        private bool m_isNull;        private double m_real;        private double m_imaginary;         #endregion         #region [ Properties ]         /// <summary>        /// Gets a value that indicates whether the complex number is null.        /// </summary>        public bool IsNull        {            get            {                return m_isNull;            }        }         /// <summary>        /// Gets or sets the real component of a complex number.        /// </summary>        /// <remarks>        /// Usage example:        ///         /// <code>        /// DECLARE @tbl TABLE(Num COMPLEX)        /// INSERT INTO @tbl VALUES('1+5i')        /// UPDATE @tbl SET Num.Real = 5        /// SELECT Num.ToString(), Num.Real FROM @tbl        /// -- Returns [Num: 5+5i, Real: 5]        /// </code>        /// </remarks>        public double Real        {            get            {                return m_real;            }            set            {                m_real = value;            }        }         /// <summary>        /// Gets or sets the imaginary component of a complex number.        /// </summary>        /// <remarks>        /// Usage example:        ///         /// <code>        /// DECLARE @tbl TABLE(Num COMPLEX)        /// INSERT INTO @tbl VALUES('1+5i')        /// UPDATE @tbl SET Num.Imaginary = 1        /// SELECT Num.ToString(), Num.Imaginary FROM @tbl        /// -- Returns [Num: 1+1i, Imaginary: 1]        /// </code>        /// </remarks>        public double Imaginary        {            get            {                return m_imaginary;            }            set            {                m_imaginary = value;            }        }         /// <summary>        /// Gets or sets the magnitude of a complex number.        /// </summary>        /// <remarks>        /// Usage example:        ///         /// <code>        /// DECLARE @tbl TABLE(Num COMPLEX)        /// INSERT INTO @tbl VALUES('1+5i')        /// UPDATE @tbl SET Num.Magnitude = 5        /// SELECT Num.ToString(), Num.Magnitude FROM @tbl        /// -- Returns [Num: 0.98058+4.9029i, Magnitude: 5]        /// </code>        /// </remarks>        public double Magnitude        {            get            {                return Math.Sqrt(m_real * m_real + m_imaginary * m_imaginary);            }            set            {                double angle = Angle;                m_real = value * Math.Cos(angle);                m_imaginary = value * Math.Sin(angle);            }        }         /// <summary>        /// Gets or sets the angle of a complex number.        /// </summary>        /// <remarks>        /// Usage example:        ///         /// <code>        /// DECLARE @tbl TABLE(Num COMPLEX)        /// INSERT INTO @tbl VALUES('1+5i')        /// UPDATE @tbl SET Num.Angle = 1        /// SELECT Num.ToString(), Num.Angle FROM @tbl        /// -- Returns [Num: 2.75501+4.29068i, Angle: 1]        /// </code>        /// </remarks>        public double Angle        {            get            {                return Math.Atan2(m_imaginary, m_real);            }            set            {                double magnitude = Magnitude;                m_real = magnitude * Math.Cos(value);                m_imaginary = magnitude * Math.Sin(value);            }        }         #endregion         #region [ Methods ]         /// <summary>        /// Returns the complex conjugate of a complex number.        /// </summary>        /// <returns>The complex conjugate.</returns>        /// <remarks>        /// Usage example:        ///         /// <code>        /// DECLARE @complex COMPLEX = '1+5i'        /// SELECT @complex.Conjugate().ToString()        /// -- Returns 1-5i        /// </code>        /// </remarks>        [SqlMethod(OnNullCall = false, IsDeterministic = true)]        public ComplexNumber Conjugate()        {            ComplexNumber num = new ComplexNumber();            num.m_real = m_real;            num.m_imaginary = -m_imaginary;            return num;        }         /// <summary>        /// Returns the negative value of the complex number.        /// </summary>        /// <returns>The negative value.</returns>        /// <remarks>        /// Usage example:        ///         /// <code>        /// DECLARE @complex COMPLEX = '1+5i'        /// SELECT @complex.Negate().ToString()        /// -- Returns -1-5i        /// </code>        /// </remarks>        [SqlMethod(OnNullCall = false, IsDeterministic = true)]        public ComplexNumber Negate()        {            ComplexNumber num = new ComplexNumber();            num.m_real = -m_real;            num.m_imaginary = -m_imaginary;            return num;        }         /// <summary>        /// Returns the sum of two complex numbers.        /// </summary>        /// <param name="num">The number to be added to this one.</param>        /// <returns>The sum.</returns>        /// <remarks>        /// Usage example:        ///         /// <code>        /// DECLARE @complex COMPLEX = '1+5i'        /// SELECT @complex.[Add]('-5+1i').ToString()        /// -- Returns -4+6i        /// </code>        /// </remarks>        [SqlMethod(OnNullCall = false, IsDeterministic = true)]        public ComplexNumber Add(ComplexNumber num)        {            ComplexNumber result = new ComplexNumber();            result.m_real = m_real + num.m_real;            result.m_imaginary = m_imaginary + num.m_imaginary;            return result;        }         /// <summary>        /// Returns the difference of two complex numbers.        /// </summary>        /// <param name="num">The number to be subtracted from this one.</param>        /// <returns>The difference.</returns>        /// <remarks>        /// Usage example:        ///         /// <code>        /// DECLARE @complex COMPLEX = '1+5i'        /// SELECT @complex.Subtract('-5+1i').ToString()        /// -- Returns 6+4i        /// </code>        /// </remarks>        [SqlMethod(OnNullCall = false, IsDeterministic = true)]        public ComplexNumber Subtract(ComplexNumber num)        {            ComplexNumber result = new ComplexNumber();            result.m_real = m_real - num.m_real;            result.m_imaginary = m_imaginary - num.m_imaginary;            return result;        }         /// <summary>        /// Returns the product of two complex numbers.        /// </summary>        /// <param name="num">The number to be multiplied with this one.</param>        /// <returns>The product.</returns>        /// <remarks>        /// Usage example:        ///         /// <code>        /// DECLARE @complex COMPLEX = '1+5i'        /// SELECT @complex.Multiply('-5+1i').ToString()        /// -- Returns -10-24i        /// </code>        /// </remarks>        [SqlMethod(OnNullCall = false, IsDeterministic = true)]        public ComplexNumber Multiply(ComplexNumber num)        {            ComplexNumber result = new ComplexNumber();            result.SetPhasor(Magnitude * num.Magnitude, Angle + num.Angle);            return result;        }         /// <summary>        /// Returns the quotient of two complex numbers.        /// </summary>        /// <param name="num">The number to divide by this one.</param>        /// <returns>The quotient.</returns>        /// <remarks>        /// Usage example:        ///         /// <code>        /// DECLARE @complex COMPLEX = '1+5i'        /// SELECT @complex.Divide('-5+1i').ToString()        /// -- Returns -1i        /// </code>        /// </remarks>        [SqlMethod(OnNullCall = false, IsDeterministic = true)]        public ComplexNumber Divide(ComplexNumber num)        {            ComplexNumber result = new ComplexNumber();            result.SetPhasor(Magnitude / num.Magnitude, Angle - num.Angle);            return result;        }         /// <summary>        /// Sets the real and imaginary components of the complex number.        /// </summary>        /// <param name="real">The real component.</param>        /// <param name="imaginary">The imaginary component.</param>        /// <remarks>        /// Usage example:        ///         /// <code>        /// DECLARE @tbl TABLE(Num COMPLEX)        /// INSERT INTO @tbl VALUES('1+5i')        /// UPDATE @tbl SET Num.SetRect(-5, 1)        /// SELECT Num.ToString() FROM @tbl        /// -- Returns -5+1i        /// </code>        /// </remarks>        [SqlMethod(IsMutator = true, OnNullCall = false)]        public void SetRect(double real, double imaginary)        {            m_real = real;            m_imaginary = imaginary;        }         /// <summary>        /// Sets the magnitude and angle of the vector described by a complex number.        /// </summary>        /// <param name="magnitude">The magnitude.</param>        /// <param name="angle">The angle.</param>        /// <remarks>        /// Usage example:        ///         /// <code>        /// DECLARE @tbl TABLE(Num COMPLEX)        /// INSERT INTO @tbl VALUES('1+5i')        /// UPDATE @tbl SET Num.SetPhasor(-5, 1)        /// SELECT Num.ToString() FROM @tbl        /// -- Returns -2.70151-4.20735i        /// </code>        /// </remarks>        [SqlMethod(IsMutator = true, OnNullCall = false)]        public void SetPhasor(double magnitude, double angle)        {            m_real = magnitude * Math.Cos(angle);            m_imaginary = magnitude * Math.Sin(angle);        }         /// <summary>        /// Returns the string representation of a complex number.        /// </summary>        /// <returns>The string representation of the complex number.</returns>        public override string ToString()        {            StringBuilder image = new StringBuilder();            double real = Math.Round(m_real, 5);            double imaginary = Math.Round(m_imaginary, 5);             if (real == 0.0D && imaginary == 0.0D)                return "0";             if (real != 0.0D)                image.Append(real);             if (imaginary != 0.0D)            {                image.Append(imaginary > 0.0D ? "+" : "-");                image.Append(Math.Abs(imaginary));                image.Append('i');            }             return image.ToString();        }         #endregion         #region [ Static ]         // Static Properties         /// <summary>        /// Gets a value that represents a null complex number.        /// </summary>        public static ComplexNumber Null        {            get            {                ComplexNumber num = new ComplexNumber();                num.m_isNull = true;                return num;            }        }         // Static Methods         /// <summary>        /// Converts the string representation of a complex number to a complex number.        /// </summary>        /// <param name="str">The string representation of a complex number.</param>        /// <returns>The complex number.</returns>        [SqlMethod(OnNullCall = false)]        public static ComplexNumber Parse(SqlString str)        {            // Regex pattern to match a single number            const string NumberPattern = @"(?<Number>[+-]?(?:[ij][0-9eE\.]+|[0-9eE\.]+[ij]?))";             // Regex pattern to match the operator            const string OperatorPattern = @"(?<Operator>[+-])";             // Regex pattern to match the whole complex number            //            const string Pattern = @"^" +               // Start of string                                   @"\s*" +             // Whitespace                                   NumberPattern +      // Number                                   @"\s*" +             // Whitespace                                   "(?:" +              // Start of optional of noncapturing group                                   OperatorPattern +    // Operator                                   @"\s*" +             // Whitespace                                   NumberPattern +      // Number                                   @"\s*" +             // Whitespace                                   ")?" +               // End of optional noncapturing group                                   "$";                 // End of string             Match match;            CaptureCollection numberCaptures;            CaptureCollection operatorCaptures;             double op = 1.0;            double real = 0.0D;            double imaginary = 0.0D;             // Parses the string as a double by first removing the i or j            Func<string, double> parse = s => double.Parse(Regex.Replace(s, "[ij]", ""));            Func<string, bool> isImaginary = s => Regex.IsMatch(s, "[ij]");             ComplexNumber num;             if (str.IsNull)                return Null;             match = Regex.Match(str.Value, Pattern);             // String format is invalid if regex does not match            if (!match.Success)                throw new FormatException("Input string was not in a correct format.");             // Get the captures for the Number and Operator groups            numberCaptures = match.Groups["Number"].Captures;            operatorCaptures = match.Groups["Operator"].Captures;             // If the string defines two numbers, ensure that exactly one of them is imaginary            if (numberCaptures.Count == 2 && !(isImaginary(numberCaptures[0].Value) ^ isImaginary(numberCaptures[1].Value)))                throw new FormatException("Input string was not in a correct format.");             // Parse the first capture group to the            // appropriate part of the complex number            if (isImaginary(numberCaptures[0].Value))                imaginary = parse(numberCaptures[0].Value);            else                real = parse(numberCaptures[0].Value);             if (numberCaptures.Count == 2)            {                // Determine if the sign needs to be                // inverted based on the operator                if (operatorCaptures[0].Value == "-")                    op = -1.0;                 // Parse the second capture group to the                // appropriate part of the complex number                if (isImaginary(numberCaptures[1].Value))                    imaginary = op * parse(numberCaptures[1].Value);                else                    real = op * parse(numberCaptures[1].Value);            }             // Return the complex number            num = new ComplexNumber();            num.m_real = real;            num.m_imaginary = imaginary;            return num;        }         #endregion    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t