Ejemplo n.º 1
0
        unsafe static internal AdjustedMantissa ParseLongMantissa(char *first, char *last, char decimal_separator)
        {
            DecimalInfo d = DecimalInfo.parse_decimal(first, last, decimal_separator);

            return(ComputeFloat(d));
        }
Ejemplo n.º 2
0
        public override void ParseValue(string Values)
        {
            this.IsValid = true;
            this.ValueList.Clear();
            foreach (var Value in Values.Split(OrDelimiter))
            {
                //        var DtoSearchParameterNumber = new SearchQueryQuantityValue();
                if (this.Modifier.HasValue && this.Modifier == SearchModifierCode.Missing)
                {
                    bool?IsMissing = SearchQueryQuantityValue.ParseModifierEqualToMissing(Value);
                    if (IsMissing.HasValue)
                    {
                        this.ValueList.Add(new SearchQueryQuantityValue(IsMissing.Value, null, null, null, null, null, null));
                    }
                    else
                    {
                        this.InvalidMessage = $"Found the {SearchModifierCode.Missing.GetCode()} Modifier yet is value was expected to be true or false yet found '{Value}'. ";
                        this.IsValid        = false;
                        break;
                    }
                }
                else
                {
                    //Examples:
                    //Syntax: [parameter]=[prefix][number]|[system]|[code] matches a quantity with the given unit
                    //Observation?value=5.4|http://unitsofmeasure.org|mg
                    //Observation?value=5.4||mg
                    //Observation?value=le5.4|http://unitsofmeasure.org|mg
                    //Observation?value=ap5.4|http://unitsofmeasure.org|mg

                    //Observation?value=ap5.4
                    //Observation?value=ap5.4|
                    //Observation?value=ap5.4|http://unitsofmeasure.org
                    //Observation?value=ap5.4|http://unitsofmeasure.org|

                    string[]         Split  = Value.Trim().Split(VerticalBarDelimiter);
                    SearchComparator?Prefix = SearchQueryDateTimeValue.GetPrefix(Split[0]);
                    if (!SearchQueryQuantityValue.ValidatePreFix(this.SearchParamTypeId, Prefix) && Prefix.HasValue)
                    {
                        this.InvalidMessage = $"The search parameter had an unsupported prefix of '{Prefix.Value.GetCode()}'. ";
                        this.IsValid        = false;
                        break;
                    }
                    string NumberAsString = SearchQueryDateTimeValue.RemovePrefix(Split[0], Prefix).Trim();
                    if (Split.Count() == 1)
                    {
                        if (Decimal.TryParse(NumberAsString, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out decimal TempDecimal))
                        {
                            DecimalInfo DecimalInfo = DecimalSupport.GetDecimalInfo(TempDecimal);
                            var         DtoSearchParameterNumber = new SearchQueryQuantityValue(false,
                                                                                                Prefix,
                                                                                                null,
                                                                                                null,
                                                                                                DecimalInfo.Precision,
                                                                                                DecimalInfo.Scale,
                                                                                                TempDecimal);
                            this.ValueList.Add(DtoSearchParameterNumber);
                        }
                        else
                        {
                            this.InvalidMessage = $"Expected a Quantity value yet was unable to parse the provided value '{NumberAsString}' as a Decimal. ";
                            this.IsValid        = false;
                            break;
                        }
                    }
                    else if (Split.Count() == 2)
                    {
                        if (Decimal.TryParse(NumberAsString, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out decimal TempDecimal))
                        {
                            string?System;
                            if (!string.IsNullOrWhiteSpace(Split[1].Trim()))
                            {
                                System = Split[1].Trim();
                            }
                            else
                            {
                                System = null;
                            }
                            DecimalInfo DecimalInfo = DecimalSupport.GetDecimalInfo(TempDecimal);
                            var         DtoSearchParameterNumber = new SearchQueryQuantityValue(false,
                                                                                                Prefix,
                                                                                                System,
                                                                                                null,
                                                                                                DecimalInfo.Precision,
                                                                                                DecimalInfo.Scale,
                                                                                                TempDecimal);

                            this.ValueList.Add(DtoSearchParameterNumber);
                        }
                        else
                        {
                            this.InvalidMessage = $"Expected a Quantity value yet was unable to parse the provided value '{NumberAsString}' as a Decimal. ";
                            this.IsValid        = false;
                            break;
                        }
                    }
                    else if (Split.Count() == 3)
                    {
                        if (Decimal.TryParse(NumberAsString, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out decimal TempDecimal))
                        {
                            string?System = null;
                            if (!string.IsNullOrWhiteSpace(Split[1].Trim()))
                            {
                                System = Split[1].Trim();
                            }

                            string?Code = null;
                            if (!string.IsNullOrWhiteSpace(Split[2].Trim()))
                            {
                                Code = Split[2].Trim();
                            }
                            DecimalInfo DecimalInfo = DecimalSupport.GetDecimalInfo(TempDecimal);
                            var         DtoSearchParameterNumber = new SearchQueryQuantityValue(false,
                                                                                                Prefix,
                                                                                                System,
                                                                                                Code,
                                                                                                DecimalInfo.Precision,
                                                                                                DecimalInfo.Scale,
                                                                                                TempDecimal);

                            this.ValueList.Add(DtoSearchParameterNumber);
                        }
                        else
                        {
                            this.InvalidMessage = $"Expected a Quantity value yet was unable to parse the provided value '{NumberAsString}' as a Decimal. ";
                            this.IsValid        = false;
                            break;
                        }
                    }
                    else
                    {
                        this.InvalidMessage = $"Expected a Quantity value type yet found to many {VerticalBarDelimiter} Delimiters. ";
                        this.IsValid        = false;
                        break;
                    }
                }
            }
            if (ValueList.Count > 1)
            {
                this.HasLogicalOrProperties = true;
            }

            if (this.ValueList.Count == 0)
            {
                this.InvalidMessage = $"Unable to parse any values into a {this.GetType().Name} from the string: {Values}.";
                this.IsValid        = false;
            }
        }
Ejemplo n.º 3
0
        internal static AdjustedMantissa ComputeFloat(DecimalInfo d)
        {
            AdjustedMantissa answer = new AdjustedMantissa();

            if (d.num_digits == 0)
            {
                // should be zero
                answer.power2   = 0;
                answer.mantissa = 0;
                return(answer);
            }
            // At this point, going further, we can assume that d.num_digits > 0.
            //
            // We want to guard against excessive decimal point values because
            // they can result in long running times. Indeed, we do
            // shifts by at most 60 bits. We have that log(10**400)/log(2**60) ~= 22
            // which is fine, but log(10**299995)/log(2**60) ~= 16609 which is not
            // fine (runs for a long time).
            //
            if (d.decimal_point < -324)
            {
                // We have something smaller than 1e-324 which is always zero
                // in binary64 and binary32.
                // It should be zero.
                answer.power2   = 0;
                answer.mantissa = 0;
                return(answer);
            }
            else if (d.decimal_point >= 310)
            {
                // We have something at least as large as 0.1e310 which is
                // always infinite.
                answer.power2   = FloatBinaryConstants.infinite_power;
                answer.mantissa = 0;
                return(answer);
            }
            const int           max_shift  = 60;
            const uint          num_powers = 19;
            ReadOnlySpan <byte> powers     = new byte[] {
                0, 3, 6, 9, 13, 16, 19, 23, 26, 29,                   //
                33, 36, 39, 43, 46, 49, 53, 56, 59,                   //
            };
            int exp2 = 0;

            while (d.decimal_point > 0)
            {
                uint n     = (uint)(d.decimal_point);
                int  shift = (n < num_powers) ? powers[(int)n] : max_shift;

                d.decimal_right_shift(shift);
                if (d.decimal_point < -Constants.decimal_point_range)
                {
                    // should be zero
                    answer.power2   = 0;
                    answer.mantissa = 0;
                    return(answer);
                }
                exp2 += (int)(shift);
            }
            // We shift left toward [1/2 ... 1].
            while (d.decimal_point <= 0)
            {
                int shift;
                if (d.decimal_point == 0)
                {
                    if (d.digits[0] >= 5)
                    {
                        break;
                    }
                    if (d.digits[0] < 2)
                    {
                        shift = 2;
                    }
                    else
                    {
                        shift = 1;
                    }
                }
                else
                {
                    uint n = (uint)(-d.decimal_point);
                    shift = (n < num_powers) ? powers[(int)n] : max_shift;
                }

                d.decimal_left_shift(shift);

                if (d.decimal_point > Constants.decimal_point_range)
                {
                    // we want to get infinity:
                    answer.power2   = FloatBinaryConstants.infinite_power;
                    answer.mantissa = 0;
                    return(answer);
                }
                exp2 -= (int)(shift);
            }
            // We are now in the range [1/2 ... 1] but the binary format uses [1 ... 2].
            exp2--;

            int min_exp = FloatBinaryConstants.minimum_exponent;

            while ((min_exp + 1) > exp2)
            {
                int n = (int)((min_exp + 1) - exp2);
                if (n > max_shift)
                {
                    n = max_shift;
                }
                d.decimal_right_shift(n);
                exp2 += (int)(n);
            }
            if ((exp2 - min_exp) >= FloatBinaryConstants.infinite_power)
            {
                answer.power2   = FloatBinaryConstants.infinite_power;
                answer.mantissa = 0;
                return(answer);
            }

            int mantissa_size_in_bits = FloatBinaryConstants.mantissa_explicit_bits + 1;

            d.decimal_left_shift((int)mantissa_size_in_bits);

            ulong mantissa = d.round();

            // It is possible that we have an overflow, in which case we need
            // to shift back.
            if (mantissa >= ((ulong)(1) << mantissa_size_in_bits))
            {
                d.decimal_right_shift(1);
                exp2    += 1;
                mantissa = d.round();
                if ((exp2 - min_exp) >= FloatBinaryConstants.infinite_power)
                {
                    answer.power2   = FloatBinaryConstants.infinite_power;
                    answer.mantissa = 0;
                    return(answer);
                }
            }
            answer.power2 = exp2 - min_exp;
            if (mantissa < ((ulong)(1) << FloatBinaryConstants.mantissa_explicit_bits))
            {
                answer.power2--;
            }
            answer.mantissa = mantissa & (((ulong)(1) << FloatBinaryConstants.mantissa_explicit_bits) - 1);

            return(answer);
        }