1%%	options
2
3copyright owner	=	Dirk Krause
4copyright year	=	2015-xxxx
5SPDX-License-Identifier:	BSD-3-Clause
6
7
8%%	header
9
10/**	@file
11	Arithmetic operations on long.
12
13	CRT on Windows: Optional.
14*/
15
16#ifndef DK4CONF_H_INCLUDED
17#if DK4_BUILDING_DKTOOLS4
18#include "dk4conf.h"
19#else
20#include <dktools-4/dk4conf.h>
21#endif
22#endif
23
24#ifndef DK4TYPES_H_INCLUDED
25#if DK4_BUILDING_DKTOOLS4
26#include <libdk4base/dk4types.h>
27#else
28#include <dktools-4/dk4types.h>
29#endif
30#endif
31
32#ifndef DK4ERROR_H_INCLUDED
33#if DK4_BUILDING_DKTOOLS4
34#include <libdk4base/dk4error.h>
35#else
36#include <dktools-4/dk4error.h>
37#endif
38#endif
39
40
41
42#ifdef __cplusplus
43extern "C" {
44#endif
45
46/**	Absolute value.
47	@param	a	Operand.
48	@param	erp	Error report, may be NULL.
49	@return	Result on success, LONG_MAX if a is LONG_MIN
50	(overflow is reported in erp).
51
52	Error codes: DK4_E_OVERFLOW.
53*/
54long
55dk4ma_long_abs(long a, dk4_er_t *erp);
56
57/**	Addition.
58	@param	a	Left operand.
59	@param	b	Right operand.
60	@param	erp	Error report, may be NULL.
61	@return	Result on success, least significant result bits
62	on overflow (see ec component of erp).
63
64	Error codes: DK4_E_OVERFLOW.
65*/
66long
67dk4ma_long_add(long a, long b, dk4_er_t *erp);
68
69/**	Subtraction.
70	@param	a	Left operand.
71	@param	b	Right operand.
72	@param	erp	Error report, may be NULL.
73	@return	Result on success, least significant result bits
74	on overflow (see ec component of erp).
75
76	Error codes: DK4_E_OVERFLOW.
77*/
78long
79dk4ma_long_sub(long a, long b, dk4_er_t *erp);
80
81/**	Multiplication.
82	@param	a	Left factor.
83	@param	b	right factor.
84	@param	erp	Error report, may be NULL.
85	@return	Result on success, least significant
86	bits on overflow (see ec component of erp).
87
88	Error codes: DK4_E_OVERFLOW.
89*/
90long
91dk4ma_long_mul(long a, long b, dk4_er_t *erp);
92
93/**	Division.
94	@param	a	Counter (left operand).
95	@param	b	Denominator (right operand).
96	@param	erp	Error report, may be NULL.
97	@return	Division result on success,
98	LONG_MIN, LONG_MAX, or 0 on division by zero or overflow
99	(see the ec component of erp).
100
101	Error codes: DK4_E_OVERFLOW, DK4_E_DIVZERO.
102*/
103long
104dk4ma_long_div(long a, long b, dk4_er_t *erp);
105
106/**	Convert dk4_im_t value to long.
107	@param	i	Value to convert.
108	@param	erp	Error report, may be NULL.
109	@return	Conversion result.
110
111	Error codes: DK4_E_OVERFLOW.
112*/
113long
114dk4ma_long_from(dk4_im_t i, dk4_er_t *erp);
115
116/**	Convert double to long.
117	@param	d	Value to convert.
118	@param	erp	Error report, may be NULL.
119	@return	Conversion result.
120
121	Error codes: DK4_E_OVERFLOW.
122*/
123long
124dk4ma_long_from_double(double d, dk4_er_t *erp);
125
126#ifdef __cplusplus
127}
128#endif
129
130
131%%	module
132
133#include "dk4conf.h"
134#include <libdk4base/dk4types.h>
135#include <libdk4base/dk4error.h>
136#include <libdk4base/dk4numco.h>
137#include <libdk4ma/dk4maal.h>
138
139
140
141long
142dk4ma_long_abs(long a, dk4_er_t *erp)
143{
144  if (LONG_MIN == a) {
145    dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
146  }
147  return ((0L <= a) ? a : ((LONG_MIN == a) ? LONG_MAX : (0L - a)));
148}
149
150
151
152long
153dk4ma_long_add(long a, long b, dk4_er_t *erp)
154{
155  if ((0L < a) && (0L < b)) {
156    if ((LONG_MAX - a) < b) {
157      dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
158    }
159  } else {
160    if ((0L > a) && (0L > b)) {
161      if (LONG_MIN == a) {
162        dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
163      } else {
164        if ((LONG_MIN - a) > b) {
165	  dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
166	}
167      }
168    }
169  }
170  return (a + b);
171}
172
173
174
175long
176dk4ma_long_sub(long a, long b, dk4_er_t *erp)
177{
178  if ((0L < a) && (0L > b)) {
179    if ((LONG_MAX + b) < a) {
180      dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
181    }
182  } else {
183    if ((0L > a) && (0L < b)) {
184      if ((LONG_MIN + b) > a) {
185        dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
186      }
187    }
188  }
189  return (a - b);
190}
191
192
193
194long
195dk4ma_long_mul(long a, long b, dk4_er_t *erp)
196{
197  if ((0L != a) && (0L != b)) {
198    if (LONG_MIN == a) {
199      if (1L != b) {
200        dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
201      }
202    } else {
203      if (LONG_MIN == b) {
204        if (1L != a) {
205	  dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
206	}
207      } else {
208        if (0L < a) {
209	  if (0L < b) {
210	    if ((LONG_MAX / a) < b) {
211	      dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
212	    }
213	  } else {
214	    if ((LONG_MIN / a) > b) {
215	      dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
216	    }
217	  }
218	} else {
219	  if (0L < b) {
220	    if ((LONG_MIN / b) > a) {
221	      dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
222	    }
223	  } else {
224	    if ((LONG_MAX / (0L - a)) < (0L - b)) {
225	      dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
226	    }
227	  }
228	}
229      }
230    }
231  }
232  return (a * b);
233}
234
235
236
237long
238dk4ma_long_div(long a, long b, dk4_er_t *erp)
239{
240  long		back	=	0;
241  if (0L != b) {
242    if ((LONG_MIN == a) && (-1L == b)) {
243      back = LONG_MAX;
244      dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
245    } else {
246      back = a / b;
247    }
248  } else {
249    if (0L < a) {
250      back = LONG_MAX;
251    } else {
252      if (0L > a) {
253        back = LONG_MIN;
254      }
255    }
256    dk4error_set_simple_error_code(erp, DK4_E_MATH_DIVZERO);
257  }
258  return back;
259}
260
261
262
263long
264dk4ma_long_from(dk4_im_t i, dk4_er_t *erp)
265{
266	if (((dk4_im_t)(LONG_MAX) < i) || ((dk4_im_t)(LONG_MIN) > i)) {
267		dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
268	}
269	return ((long)i);
270}
271
272
273
274long
275dk4ma_long_from_double(double d, dk4_er_t *erp)
276{
277	long	back	= 0L;
278	if ((double)(LONG_MIN) > d) {
279		dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
280		back = LONG_MIN;
281	}
282	else {
283		if ((double)(LONG_MAX) < d) {
284			dk4error_set_simple_error_code(erp,DK4_E_MATH_OVERFLOW);
285			back = LONG_MAX;
286		}
287		else {
288			back = (long)d;
289		}
290	}
291	return back;
292}
293