Перейти к содержанию

Глобальные функции

Материал из Химсофт Вики

Общие сведения

Функции, вынесенные в глобальную видимость через объект Code, позволяют централизованно управлять логикой форматирования данных.

Это избавляет от необходимости дублировать код в каждом отдельном макете и обеспечивает единообразие расчетов во всех отчетах.

Rounding.RoundBase()

Предназначена для гибкого округления числовых значений.

В отличие от стандартных функций, она поддерживает работу с отрицательными разрядами и округление до значащих цифр.

Входные параметры

  • value (Double) - исходное число для обработки;
  • digits (Object)
    • при Mode = 1 - количество знаков после запятой (положительное) или до запятой (отрицательное);
    • при Mode = 0 - количество значащих цифр;
  • mode (Object) - режим работы:
    • 1 (ToDecimalPlace) - десятичное округление;
    • 0 (ToSignificantPlace) - значащие цифры.

Выходные параметры

  • String - возвращает строковое представление числа.

Алгоритм

Функция работает по методу Away From Zero (округление от нуля).

Режим 1 (десятичное округление):

  • вычисляется множитель;
  • число умножается на множитель, округляется до целого и делится обратно;
  • при положительном n результат форматируется с фиксированным количеством нулей после запятой.

Режим 0 (значащие цифры):

  • определяется порядок числа через десятичный логарифм;
  • вычисляется масштабный коэффициент, чтобы оставить ровно n цифр;
  • число масштабируется, округляется и возвращается в исходный порядок;
  • результат преобразуется в компактную строку (удаляются лишние нули в конце).

Примеры использования в дизайнере-конструкторе

Исходное значение Синтаксис в соответствии с формулой =Code.Rounding.RoundBase(x, n, m) Результат
12345
=Code.Rounding.RoundBase(ReportItems!variable.Value, 2, 1)
12345,00
12345.00
=Code.Rounding.RoundBase(ReportItems!variable.Value, 0, 1)
12345
12345.01
=Code.Rounding.RoundBase(ReportItems!variable.Value, -2, 1)
12300
555.55
=Code.Rounding.RoundBase(ReportItems!variable.Value, 1, 0)
600

Предварительный вариант на VB.NET

Public Function RoundBase(ByVal xValue As Double, ByVal nDigits As Integer, ByVal mMode As Integer) As String
	
	If xValue = 0 Then Return "0"
	
	'Проверка аргумента nDigits, является ли пустым, остутствующим в БД или пустой строкой
	Dim nDigitsFlag As Boolean = True
	If nDigits Is Nothing OrElse IsDBNull(nDigits) OrElse String.IsNullOrEmpty(nDigits.ToString().Trim()) Then
		nDigitsFlag = False
	End If
	
	'Проверка аргумента mMode, является ли пустым, остутствующим в БД или пустой строкой
	Dim mModeFlag As Boolean = True
	If mMode Is Nothing OrElse IsDBNull(mMode) OrElse String.IsNullOrEmpty(mMode.ToString().Trim()) Then
		mModeFlag = False
	End If
	
	'Если хотя бы один из параметров (nDigits или mMode) отсутствует, возвращается исходное число xValue
	If (nDigitsFlag = False) Or (mModeFlag = False)
		Return xValue
	End If
	
	If mMode = 1 Then
		' Округление до n знаков после запятой
		' В отличие от стандартной функции Math.Round(value, digits, MidpointRounding.AwayFromZero)
		' может работать с отрицательными digits за счет сдвига
		
		' Вычисление множителя
		Dim factor As Double = Math.Pow(10, nDigits)
		
		' Свдиг запятой на расстояние множителя, округление до целого, обратный сдвиг
		' Направление сдвига зависит от знака (+-) в nDigits
		Dim result As Double = Math.Round(xValue * factor, 0, MidpointRounding.AwayFromZero) / factor
		
		' Форматирование результата (либо до целого(0), либо по положительному nDigits)
		Return result.ToString("F" & Math.Max(0, nDigits))
	End If	
			
	If mMode = 0 Then
		' Округление до n значащих цифр     
		
		' Определение порядка числа (до запятой)
		Dim scale As Double = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(xValue))) + 1 - nDigits)
		
		' Свдиг запятой влево (уменьшение порядка числа), округление, сдвиг вправо (увеличение порядка числа)
		Dim result As Double = Math.Round(xValue / scale, 0, MidpointRounding.AwayFromZero) * scale
		
		' Форматирование результата в компактную строку (удаление лишних нулей, научная нотация)
		Return result.ToString("G")	
	End If		
	
	' При некорректном значении режима mMode
	Return ""
	
End Function

Итоговый вариант на С#

public class Rounding
{
    public string RoundBase(double value, int digits, RoundMode mode)
    {
        if (value == 0) 
            return "0";

        double result;
        switch (mode)
        {
            case RoundMode.ToDecimalPlace:
                double factor = Math.Pow(10, digits);
                result = Math.Round(value * factor, 0, MidpointRounding.AwayFromZero) / factor;
                return result.ToString("F" + Math.Max(0, digits));
            case RoundMode.ToSignificantPlace:
                double scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(value))) + 1 - digits);
                result = Math.Round(value / scale, 0, MidpointRounding.AwayFromZero) * scale;
                return result.ToString("G");
            default:
                throw new ArgumentOutOfRangeException(nameof(mode), "Некорректный режим округления");
        }
    }
    
    public string RoundBase(double value, int digits, int mode) => RoundBase(value, digits, (RoundMode)mode);
}