unsafe static internal AdjustedMantissa ParseLongMantissa(char *first, char *last, char decimal_separator) { DecimalInfo d = DecimalInfo.parse_decimal(first, last, decimal_separator); return(ComputeFloat(d)); }
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; } }
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); }