Числові операції
Арифметика в ABAP — не просто + і -: важливий calculation type (який тип результату отримаєш), правила округлення при змішаних типах і вибір правильного типу даних для задачі. Помилки тут мовчазні — 1 / 3 присвоєне у i дасть 0, 0.815 у f — це 8.1499999999999995E-01. Ця сторінка збирає те, що треба знати, щоб не наступати.
Числові типи
Section titled “Числові типи”| Тип | Розмір | Діапазон | Коли брати |
|---|---|---|---|
i | 4 байти | ±2 147 483 647 | лічильники, індекси, sy-index, sy-tabix |
int8 | 8 байтів | ±9.2·10^18 | якщо i замалий |
p LENGTH n DECIMALS d | 1-16 байтів | залежить від довжини | фіксовані десяткові — суми, ваги, кількості |
decfloat16 | 8 байтів | 16 десяткових розрядів | високоточні десяткові обчислення |
decfloat34 | 16 байтів | 34 десяткових розряди | максимальна точність без big int |
f | 8 байтів | мантиса + експонента | швидкі обчислення, точність не критична |
Тип n — не числовий, це символьний із цифрами. Для розрахунків не бери; використовуй для ID та артикулів.
DATA i_a TYPE i VALUE 3.DATA int8_a TYPE int8 VALUE 1.
" Packed: ± 15 значущих цифр для LENGTH 8, з них 2 на дробову частинуDATA p_val TYPE p LENGTH 8 DECIMALS 2 VALUE '1234567890123.99-'.
DATA dec16 TYPE decfloat16 VALUE '0.7805874561940696'.DATA dec34 TYPE decfloat34 VALUE '0.0587780463975441530508753423121495'.
" Binary float — обережно, не точнийDATA float TYPE f VALUE '2.1643779466775481E-01'.float = CONV f( '0.815' ). " 8.1499999999999995E-01DATA(dec_b) = CONV decfloat34( '0.815' ). " 0.815ASSERT float <> dec_b.Узагальнені типи
Section titled “Узагальнені типи”Узагальнені типи (numeric, p, decfloat) дозволяють писати код, що працює з будь-якою спеціалізацією. Використовуються для field symbols і параметрів методів.
FIELD-SYMBOLS <num> TYPE numeric. " приймає все числовеFIELD-SYMBOLS <p> TYPE p. " тільки packedFIELD-SYMBOLS <d> TYPE decfloat. " decfloat16 і decfloat34
ASSIGN i_a TO <num>.ASSIGN dec16 TO <d>.ASSIGN p_val TO <p>.Нотації для літералів
Section titled “Нотації для літералів”Оскільки більшість типів (крім i) не можна задати напряму — їх записують як character-літерали:
DATA(math) = `- 123.45`. " математична: знак зліва, пробіл опційнийDATA(comm) = `123.45-`. " комерційна: знак справаDATA(sci) = `-1.23456E03`. " науковаЩо який тип приймає:
| Тип | math | comm | sci |
|---|---|---|---|
decfloat16/34 | так | так | так |
f | так (без пробілу після знака) | так | так |
i, int8, p | так | так | ні (CX_SY_CONVERSION_NO_NUMBER) |
Арифметичні оператори
Section titled “Арифметичні оператори”+, -, *, /, DIV, MOD, **.
DATA res TYPE i.
res = 7 DIV 3. " 2 — цілочисельна частинаres = 7 MOD 3. " 1 — залишок (завжди додатний)res = 2 ** 5. " 32 — піднесення до степеняПріоритет стандартний: ** > * / DIV MOD > + -. Дужки пріоритезують обчислення всередині.
Винятки при обчисленнях
Section titled “Винятки при обчисленнях”" Ділення на нульTRY. res = 1 / 0. CATCH cx_sy_zerodivide.ENDTRY.
" 0/0 — НЕ викидає виняток, результат просто 0res = 0 / 0. " 0
" ПереповненняTRY. res = 2147483647 + 1. " max_i + 1 CATCH cx_sy_arithmetic_overflow.ENDTRY.Оператор ** і тип f
Section titled “Оператор ** і тип f”** зазвичай дає результат типу f. Якщо не хочеш binary float — бери функцію ipow:
DATA(a) = 2 ** 5. " тип f (!)DATA(b) = ipow( base = 2 exp = 3 ). " тип i, результат 8Calculation assignments
Section titled “Calculation assignments”a += b. " a = a + ba -= b. " a = a - ba *= b. " a = a * ba /= b. " a = a / bCalculation type
Section titled “Calculation type”Calculation type — тип проміжних обчислень у виразі. Визначається за найбільшим з учасників за таким порядком пріоритету:
decfloat34— якщо хоч один учасникdecfloat34decfloat16— якщо хоч одинdecfloat16f— якщо хоч одинf(крім ситуацій з decfloat)p— якщо хоч одинpint8— якщо хоч одинint8i— інакше
Конверсії нечислових типів: d, t, x, xstring → i; c, n, string → p; utclong — не підтримується.
DATA(r1) = 1 + CONV decfloat34( '1.1' ). " decfloat34DATA(r2) = CONV decfloat16( '2.2' ) + 5. " decfloat16DATA(r3) = 1 + CONV f( '2.23645E-01' ). " fDATA(r4) = CONV int8( 2 ) + 2. " int8DATA(r5) = 2 + 5. " iLossless calculations через EXACT
Section titled “Lossless calculations через EXACT”EXACT перевіряє, що при присвоєнні/обчисленні не відбулось небажаного округлення — інакше викидає CX_SY_CONVERSION_ROUNDING:
TYPES ty_pl8d2 TYPE p LENGTH 8 DECIMALS 2.
DATA(ok) = EXACT ty_pl8d2( 1 / 4 ). " 0.25 — ок
TRY. DATA(bad) = EXACT ty_pl8d2( 1 / 3 ). " потрібне округлення → виняток CATCH cx_sy_conversion_rounding.ENDTRY.Вбудовані числові функції
Section titled “Вбудовані числові функції”" Абсолютна величина і знакabs( -4 ). " 4sign( -789 ). " -1 (0 якщо 0, 1 якщо додатне)
" Округленняceil( CONV decfloat34( '4.001' ) ). " 5 — вгору до цілогоfloor( CONV decfloat34( '4.999' ) ). " 4 — вниз до цілогоtrunc( CONV decfloat34( '-4.999' ) ). " -4 — ціла частина (відкидання)frac( CONV decfloat34( '4.999' ) ). " 0.999 — дробова частина
" round: до N розрядів або до precisionround( val = CONV decfloat34( '1.2374' ) dec = 2 ). " 1.24round( val = CONV decfloat34( '1234' ) prec = 3 ). " 1.23E+3
" rescale — аналогічно, з більш жорсткими правилами scale/precisionrescale( val = CONV decfloat34( '1234.56789' ) dec = 1 ). " 1234.6
" Степінь і квадратний коріньipow( base = 2 exp = 3 ). " 8 (цілочисельна, без f)sqrt( CONV decfloat34( '40.96' ) ). " 6.4
" Логарифми, тригонометріяlog10( CONV decfloat34( '1000' ) ). " 3sin( '30' ). cos( '45' ). tan( '90' )." Також: acos, asin, atan, cosh, sinh, tanh, exp, log
" Екстремуми — від 2 до 9 аргументівnmin( val1 = ... val2 = ... val3 = ... ).nmax( val1 = ... val2 = ... val3 = ... ).
" Факторіал і біноміальний коефіцієнтfactorial( 10 ). " 3628800binomial( n = 5 k = 2 ). " 10Системні класи для обчислень
Section titled “Системні класи для обчислень”cl_abap_math — межі типів
Section titled “cl_abap_math — межі типів”DATA(max_i) = cl_abap_math=>max_int4. " 2147483647DATA(max_i8) = cl_abap_math=>max_int8.DATA(max_d34) = cl_abap_math=>max_decfloat34." min_int1/2/4/8, max_int1/2, min_decfloat16/34 — усе аналогічноcl_abap_random* — випадкові числа
Section titled “cl_abap_random* — випадкові числа”DATA(rand_i) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( ) min = 1 max = 100 )->get_next( ).DATA(rand_d34) = cl_abap_random_decfloat34=>create( seed = cl_abap_random=>seed( ) )->get_next( ).DATA(rand_f) = cl_abap_random_float=>create( seed = cl_abap_random=>seed( ) )->get_next( )." Є варіанти для int8, packed, packed_dec1..dec14cl_abap_bigint — цілі довільної розрядності
Section titled “cl_abap_bigint — цілі довільної розрядності”Коли числа виходять за межі int8 — cl_abap_bigint. API fluent, всі операції повертають новий екземпляр (якщо не викликати clone, то метод модифікує той самий об’єкт).
DATA(big) = cl_abap_bigint=>factory_from_string( `283469208407283452340` ).
DATA(plus) = cl_abap_bigint=>factory_from_int4( 4 )->add( big )->to_string( ).DATA(pow) = cl_abap_bigint=>factory_from_int4( 8 )->pow( 2 )->to_string( ). " "64"DATA(sqrt1) = cl_abap_bigint=>factory_from_int4( 9 )->sqrt( )->to_string( ). " "3"
" Ділення: повертає структуру з quotient і remainderDATA(dv) = cl_abap_bigint=>factory_from_int4( 20 )->div( big ).DATA(q) = dv-quotient->to_string( ).DATA(r) = dv-remainder->to_string( ).
" Конвертаціїcl_abap_bigint=>factory_from_int4( 100 )->to_utf8( ).cl_abap_bigint=>factory_from_string( `123` )->to_df34( ).cl_abap_bigint=>factory_from_int4( -10 )->to_external( iv_flg_minus_in_front = abap_true ).cl_abap_rational — раціональні числа
Section titled “cl_abap_rational — раціональні числа”Точні дроби без округлення:
DATA(r) = cl_abap_rational=>factory_from_string( `-2/3` )->add_int4( 1 )->to_df34( )." 3.333...E-01 — як decfloat34
" Або в packedDATA result TYPE p LENGTH 16 DECIMALS 5.cl_abap_rational=>factory_from_string( `-2/3` )->add_int4( 1 )->to_dec( IMPORTING ev_decimal = result ).Обчислення з датою, часом і time stamp
Section titled “Обчислення з датою, часом і time stamp”Детально — у Дата, час і час-мітка. Коротко:
" Дати: різниця у дняхDATA d1 TYPE d VALUE '20240101'.DATA d2 TYPE d VALUE '20231227'.DATA(days) = d1 - d2. " 5
" Час: різниця у секундах (може бути від'ємною)DATA t1 TYPE t VALUE '210000'.DATA t2 TYPE t VALUE '040000'.DATA(diff_s) = ( t2 - t1 ) MOD 86400. " 25200 — абсолютна за добуDATA(hours) = diff_s DIV 3600.DATA(minutes) = ( diff_s MOD 3600 ) DIV 60.DATA(seconds) = diff_s MOD 60.
" Time stamp: utclong_add / utclong_diffDATA(ts) = utclong_current( ).DATA(ts_plus) = utclong_add( val = ts hours = 1 ).DATA(sec_diff) = utclong_diff( high = ts_plus low = ts ). " 3600Арифметика в ABAP SQL і CDS
Section titled “Арифметика в ABAP SQL і CDS”SELECT SINGLE 1 + 2 AS add, " 3 10 - -8 AS subtract, " 18 3 * 5 AS multiply, " 15
" / заборонено для цілих — треба типізовані літерали або CAST d34n`4.4` / d34n`2.2` AS divide1, " 2 CAST( 1 AS D34N ) / CAST( 2 AS D34N ) AS divide2, " 0.5
( 1 + 2 ) * 3 AS parens, " 9
" Функції div( 4, 2 ) AS idiv, " 2 (округлене до int) division( 1, 3, 2 ) AS ddiv, " 0.33 (з округленням) mod( 3, 2 ) AS md, " 1 ceil( decfloat34`1.333` ) AS c, " 2 floor( decfloat34`1.333` ) AS fl, " 1 abs( int4`-2` ) AS a, " 2 round( decfloat34`1.337`, 2 ) AS r " 1.34FROM i_timezoneINTO @DATA(wa).Адаптовано з 29_Numeric_Operations.md (Apache 2.0). Повний перелік нюансів — в оригіналі.