aboutsummaryrefslogtreecommitdiff
path: root/lib/libmpa/mpa_cmp.c
blob: c6f12a4fc7131986f2b278920870f67ddd5d9894 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// SPDX-License-Identifier: BSD-2-Clause
/*
 * Copyright (c) 2014, STMicroelectronics International N.V.
 */
#include "mpa.h"

/*************************************************************
 *
 *   HELPERS
 *
 *************************************************************/

/*  --------------------------------------------------------------------
 *  Function:   __mpa_abs_cmp
 *
 *  Returns 0  if |op1| == |op2|
 *          >0 if |op1| >  |op2|
 *          <0 if |op1| <  |op2|
 */
int __mpa_abs_cmp(const mpanum op1, const mpanum op2)
{
	int wpos;
	char same;

	/* if they're really the same, return 0 */
	if (op1 == op2)
		return 0;

	/* check the sizes */
	if (__mpanum_size(op1) != __mpanum_size(op2))
		return __mpanum_size(op1) - __mpanum_size(op2);

	if (__mpanum_is_zero(op1) && __mpanum_is_zero(op2))
		return 0;

	/* Ok, so we have the same size and they're not zero. Check words */
	wpos = __mpanum_size(op1) - 1;
	same = 1;
	while (same && (wpos >= 0)) {
		same = (op1->d[wpos] == op2->d[wpos]);
		wpos--;
	}
	if (same)
		return 0;
	wpos++;
	return (op1->d[wpos] > op2->d[wpos] ? 1 : -1);
}

/*  --------------------------------------------------------------------
 *  Function:   __mpa_abs_greater_than
 *
 *  Returns 1 if |op1| > |op2| and otherwise returns 0.
 */
int __mpa_abs_greater_than(const mpanum op1, const mpanum op2)
{
	return (__mpa_abs_cmp(op1, op2) > 0 ? 1 : 0);
}

/*  --------------------------------------------------------------------
 *  Function:   __mpa_abs_less_than
 *
 *  Returns 1 if |op1| < |op2| and otherwise returns 0.
 */
int __mpa_abs_less_than(const mpanum op1, const mpanum op2)
{
	return (__mpa_abs_cmp(op1, op2) < 0 ? 1 : 0);
}

/*************************************************************
 *
 *   LIB FUNCTIONS
 *
 *************************************************************/

/*  --------------------------------------------------------------------
 *  Function:   mpa_cmp
 *
 *  Returns 0  if op1 == op2
 *          >0 if op1 >  op2
 *          <0 if op1 <  op2
 */
int32_t mpa_cmp(const mpanum op1, const mpanum op2)
{
	int sign_1;
	int abscmp;

	/* if they have different signs, it's straight forward */
	sign_1 = __mpanum_sign(op1);
	if (sign_1 != __mpanum_sign(op2))
		return sign_1;

	/* handle the special case where op1->size = 0 */
	if (__mpanum_size(op1) == 0)
		return __mpanum_size(op2) == 0 ? 0 : -__mpanum_sign(op2);

	/* so they have the same sign. compare the abs values and decide
	 * based on sign_1.
	 */

	abscmp = __mpa_abs_cmp(op1, op2);
	if (sign_1 != MPA_POS_SIGN)
		return -abscmp;
	return abscmp;
}

/*  --------------------------------------------------------------------
 *  Function:   mpa_cmp_short
 *
 *  Compares op1 to the word_t op2 and returns:
 *      >0 if op1 > op2,
 *       0 if op1 == op2
 *      <0 if op1 < op2
 */
int32_t mpa_cmp_short(const mpanum op1, int32_t op2)
{
#if (MPA_WORD_SIZE == 32)

	int sign_1;
	int sign_2;
	mpa_word_t op2abs;

	sign_1 = __mpanum_sign(op1);
	sign_2 = (op2 < 0) ? MPA_NEG_SIGN : MPA_POS_SIGN;

	/* handle the special case where op1->size = 0 */
	if (op1->size == 0)
		return op2 == 0 ? 0 : -sign_2;

	/* check if op1 is larger than an int32_t */
	if (__mpanum_size(op1) > 1)
		return sign_1;

	/* check if they have different signs */
	if (sign_1 != sign_2)
		return sign_1;

	/* here they have the same sign and we can compare absolute values */

	op2abs = ((op2 < 0) ? (mpa_word_t) -op2 : (mpa_word_t) op2);

	if (__mpanum_lsw(op1) == op2abs)
		return 0;

	return (__mpanum_lsw(op1) > op2abs) ? sign_1 : -sign_1;

#else
#error "Write code for digit size != 32"
#endif
}