c++与数学典型算法的结合
阿姆斯特朗数
// A number is called as Armstrong number if sum of cubes of digits of number is // equal to the number itself. // For Example 153 is an Armstrong number because 153 = 1³+5³+3³. #include <stdio.h> // Function to calculate x raised to the power y int power(int x, unsigned int y) { if (y == 0) return 1; if (y % 2 == 0) return power(x, y / 2) * power(x, y / 2); return x * power(x, y / 2) * power(x, y / 2); } // Function to calculate order of the number int order(int x) { int n = 0; while (x) { n++; x = x / 10; } return n; } // Function to check whether the given number is // Armstrong number or not int isArmstrong(int x) { // Calling order function int n = order(x); int temp = x, sum = 0; while (temp) { int r = temp % 10; sum += power(r, n); temp = temp / 10; } // If satisfies Armstrong condition if (sum == x) return 1; else return 0; } // int main() { int x = 153; if (isArmstrong(x) == 1) printf("True\n"); else printf("False\n"); x = 1253; if (isArmstrong(x) == 1) printf("True\n"); else printf("False\n"); return 0; }
这段代码实现了一个函数isArmstrong
,用于检查给定的整数是否为阿姆斯特朗数。下面是代码的详细解释:
power
函数用于计算一个数的指定次幂。它使用了递归的方式来实现幂运算。当指数y
为0时,返回1;当指数是偶数时,将问题分解为两个相同的子问题,并将它们相乘;当指数是奇数时,先计算结果的一半,再将其与原始数进行相乘。order
函数用于计算一个数的位数。它通过对数学性质进行迭代计算来确定给定数的位数。在循环中,每次将给定数除以10并计数,直到数变成0为止。最后返回计数值,即为数字的位数。isArmstrong
函数用于检查一个数是否为阿姆斯特朗数。该函数首先调用order
函数获取给定数的位数,并把结果保存在变量n
中。然后,使用一个循环遍历每个位上的数字。在每次迭代中,将给定数模10得到最右边的一位数r
,然后将r
的立方加到变量sum
上。然后将给定数除以10,以便处理下一位数。最后,如果sum
等于原始数,则返回1表示该数字是阿姆斯特朗数;否则返回0表示不是。- 在
main
函数中,两个示例用例被传递给isArmstrong
函数进行检查。第一个示例是153,该数字满足阿姆斯特朗数的条件,因此输出结果为"True"。第二个示例是1253,该数字不满足条件,因此输出结果为"False"。
因此,这段代码通过使用递归、位数计算和阿姆斯特朗数条件的检查,实现了判断一个数是否为阿姆斯特朗数的功能。
## Cantor三分集
/** * @file * @brief Program to generate [Cantor ternary * set](https://en.wikipedia.org/wiki/Cantor_set) */ #include <stdio.h> #include <stdlib.h> #include <string.h> /** structure to define Cantor set */ typedef struct _cantor_set { double start; /**< start of interval */ double end; /**< end of interval */ struct _cantor_set *next; /**< pointer to next set */ } CantorSet; /** Iterative constructor of all sets in the current level. This function * dynamically allocates memory when creating new sets. These are freed by the * function ::free_memory. * @param head pointer to interval set instance to update */ void propagate(CantorSet *head) { // if input is NULL, ignore the process if (head == NULL) return; CantorSet *temp = head; // local pointer to track propagation // create new node for the new set CantorSet *newNode = (CantorSet *)malloc(sizeof(CantorSet)); // get 1/3rd of interval double diff = (((temp->end) - (temp->start)) / 3); // update interval ranges newNode->end = temp->end; temp->end = ((temp->start) + diff); newNode->start = (newNode->end) - diff; // update pointer to next set in this level newNode->next = temp->next; // point to next set temp->next = newNode; // create next set propagate(temp->next->next); } /** Print sets in the current range to `stdout` * @param head pointer to first set in the current level */ void print(CantorSet *head) { CantorSet *temp = head; while (temp != NULL) // print while a valid set is found { printf("\t"); printf("[%lf] -- ", temp->start); printf("[%lf]", temp->end); temp = temp->next; } printf("\n"); } /** Clear memory allocated by ::propagate function. * @param head pointer to first allocated instance. */ void free_memory(CantorSet *head) { if (!head) return; if (head->next) free_memory(head->next); free(head); } /** Main function */ int main(int argc, char const *argv[]) { int start_num, end_num, levels; if (argc < 2) { printf("Enter 3 arguments: start_num \t end_num \t levels\n"); scanf("%d %d %d", &start_num, &end_num, &levels); } else { start_num = atoi(argv[1]); end_num = atoi(argv[2]); levels = atoi(argv[3]); } if (start_num < 0 || end_num < 0 || levels < 0) { fprintf(stderr, "All numbers must be positive\n"); return -1; } CantorSet head = {.start = start_num, .end = end_num, .next = NULL}; // loop to propagate each level from top to bottom for (int i = 0; i < levels; i++) { printf("Level %d\t", i); print(&head); propagate(&head); printf("\n"); } printf("Level %d\t", levels); print(&head); // delete all memory allocated free_memory(head.next); return 0; }
这段代码用于生成Cantor三分集。下面是代码的详细解释:
- 首先定义了一个结构体
CantorSet
,用于表示Cantor集的区间。 propagate
函数是一个递归函数,用于构造当前级别的所有集合。该函数会动态分配内存来创建新的集合,并在后续的操作中释放这些内存。在函数中,首先检查输入指针是否为空。然后,创建一个新的节点来表示新的集合,并计算当前集合的长度的1/3。接下来,更新当前集合的范围,并将新的集合插入到当前集合后面。最后,递归调用自身来创建下一个级别的集合。print
函数用于打印当前级别的集合。该函数遍历链表中的所有集合,并按格式将每个集合的起始和结束位置打印出来。free_memory
函数用于释放propagate
函数动态分配的内存。该函数使用递归方式释放所有的内存。- 在
main
函数中,首先解析命令行参数或者从标准输入中读取起始数、结束数和级别数。然后,创建一个初始的CantorSet
对象作为链表的头部。接下来,通过循环依次构造并打印每个级别的集合。最后,通过调用free_memory
函数释放所有动态分配的内存。
因此,这段代码实现了一个程序,用于生成并打印Cantor三分集的级别。每个级别的集合是由前一个级别生成的,并且该程序支持从命令行参数或者标准输入中指定起始数、结束数和级别数。
斐波那契数
/** * @file * @brief Program to print the nth term of the Fibonacci series. * @details * Fibonacci series generally starts from 0 and 1. Every next term in * the series is equal to the sum of the two preceding terms. * For further info: https://en.wikipedia.org/wiki/Fibonacci_sequence * * @author [Luiz Carlos Aguiar C](https://github.com/IKuuhakuI) * @author [Niranjan](https://github.com/niranjank2022) */ #include <assert.h> /// for assert() #include <errno.h> /// for errno - to determine whether there is an error while using strtol() #include <stdio.h> /// for input, output #include <stdlib.h> /// for exit() - to exit the program #include <time.h> /// to calculate time taken by fib() /** * @brief Determines the nth Fibonacci term * @param number - n in "nth term" and it can't be negative as well as zero * @return nth term in unsigned type * @warning * Only till 47th and 48th fibonacci element can be stored in `int` and * `unsigned int` respectively (takes more than 20 seconds to print) */ unsigned int fib(int number) { // Check for negative integers if (number <= 0) { fprintf(stderr, "Illegal Argument Is Passed!\n"); exit(EXIT_FAILURE); } // Base conditions if (number == 1) return 0; if (number == 2) return 1; // Recursive call to the function return fib(number - 1) + fib(number - 2); } /** * @brief Get the input from the user * @return valid argument to the fibonacci function */ int getInput(void) { int num, excess_len; char buffer[3], *endPtr; while (1) { // Repeat until a valid number is entered printf("Please enter a valid number:"); fgets(buffer, 3, stdin); // Inputs the value from user excess_len = 0; if (!(buffer[0] == '\n' || buffer[1] == '\n' || buffer[2] == '\n')) { while (getchar() != '\n') excess_len++; } num = strtol(buffer, &endPtr, 10); // Attempts to convert the string to integer // Checking the input if ( // The number is too large (excess_len > 0 || num > 48) || // Characters other than digits are included in the input (*endPtr != '\0' && *endPtr != '\n') || // No characters are entered endPtr == buffer) { continue; } break; } printf("\nEntered digit: %d (it might take sometime)\n", num); return num; } /** * @brief self-test implementation * @return void */ static void test() { assert(fib(5) == 3); assert(fib(2) == 1); assert(fib(9) == 21); } /** * @brief Main function * @return 0 on exit */ int main() { // Performing the test test(); printf("Tests passed...\n"); // Getting n printf( "Enter n to find nth fibonacci element...\n" "Note: You would be asked to enter input until valid number ( less " "than or equal to 48 ) is entered.\n"); int number = getInput(); clock_t start, end; start = clock(); printf("Fibonacci element %d is %u ", number, fib(number)); end = clock(); printf("in %.3f seconds.\n", ((double)(end - start)) / CLOCKS_PER_SEC ); return 0; }
这段代码实现了一个程序,用于计算和打印斐波那契序列中第n个数字,并且支持从用户输入获取n的值。下面是代码的详细解释:
fib
函数用于计算斐波那契序列的第n个数字。该函数采用递归的方式实现。首先,检查输入参数是否为负数或零,如果是,则打印错误信息并退出程序。然后,给出了前两个基本条件:当n为1时,返回0;当n为2时,返回1。接下来,通过递归调用自身来计算第n个斐波那契数,即使用fib(n-1) + fib(n-2)。getInput
函数用于从用户获取输入。该函数会一直循环,直到输入的数字合法为止。首先,定义了一些变量用于接收用户输入和处理输入。然后,通过调用fgets
函数从标准输入中获取用户输入并存储在缓冲区中。接着,对缓冲区进行检查,以确定输入是否包含换行符以外的其他字符。如果存在其他字符,则通过循环将多余的字符都读取并丢弃。然后,通过调用strtol
函数将缓冲区中的字符串转换为整数。在转换过程中,会检查输入是否超出范围或包含非数字字符。如果输入不合法,则继续循环,要求用户重新输入。最后,返回合法的输入数字。test
函数用于执行自我测试。在该函数中,使用assert
宏来验证fib
函数输出的结果是否符合预期。通过调用assert
宏,如果测试不通过,程序会输出错误信息并终止。main
函数是程序的入口函数。首先,调用test
函数执行自我测试,并打印出测试通过的消息。然后,通过调用getInput
函数获取用户输入的n。接下来,通过调用clock
函数分别记录程序开始执行和结束执行的时间。然后,调用fib
函数计算第n个斐波那契数,并将结果打印出来。最后,再次使用clock
函数记录程序结束执行时的时间,并计算出程序的运行时间。运行时间以秒为单位进行打印。
因此,这段代码实现了一个完整的斐波那契数计算程序。它可以根据用户的输入计算并打印斐波那契序列中第n个数字,并且具备输入验证和自我测试的功能。
## 阶乘
#include <stdio.h> int main() { int a[200], n, counter, temp, i; a[0] = 1; counter = 0; printf("Enter a whole number to Find its Factorial: "); scanf("%d", &n); if (n < 0) printf("Cannot Calculate factorials for negative numbers."); else { for (; n >= 2; n--) { temp = 0; for (i = 0; i <= counter; i++) { temp = (a[i] * n) + temp; a[i] = temp % 10; temp = temp / 10; } while (temp > 0) { a[++counter] = temp % 10; temp = temp / 10; } } for (i = counter; i >= 0; i--) printf("%d", a[i]); } return 0; }
这段代码是一个用于计算输入数字的阶乘的程序。下面是代码的详细解释:
- 首先,定义了一些变量。
a
是用于存储计算结果的数组,n
用于接收用户输入的数字,counter
用于记录数组中最高位的索引,temp
用于保存中间计算结果,i
用于循环计数。 - 在程序开始时,将数组
a
的第一个元素设置为1,表示初始时的阶乘结果为1。然后将counter
设置为0,用于记录最高位的索引。 - 接下来,通过调用
printf
函数打印提示用户输入数字的消息。然后,通过调用scanf
函数从标准输入中获取用户输入的数字,并将其存储在变量n
中。 - 在进行计算之前,首先对用户输入的数字进行检查。如果输入的数字小于0,则说明无法计算阶乘,因为阶乘只能应用于非负整数。在这种情况下,通过调用
printf
函数打印错误消息。 - 如果输入的数字大于等于0,那么开始进行阶乘计算。使用一个循环,从输入的数字递减到2,每次迭代都进行一次阶乘计算。
- 在每次迭代中,首先将
temp
设置为0,用于保存中间计算结果。然后使用一个嵌套的循环,从数组a
的第一个元素到最高位的索引,依次对数组中的每一位进行乘法运算。 - 在乘法运算中,将当前数组中的值与当前迭代的数字相乘,并将结果加上之前的进位
temp
。然后,将得到的乘法结果的个位数保存在数组a
中的相应位置,而进位则保存在temp
中。这样,我们就更新了数组a
中的值,并将进位传递给下一位的乘法运算。 - 在内层循环结束后,如果
temp
大于0,则说明还有进位没有处理完。在这种情况下,使用一个循环将剩余的进位依次添加到数组a
中,同时更新最高位的索引counter
。 - 完成所有的阶乘计算后,使用一个循环从最高位到最低位,依次打印出数组
a
中的数字。注意,由于每位数字是以逆序存储的,所以需要从最高位开始打印。 - 最后,通过返回0来表示程序执行成功,并终止程序的执行。
因此,这段代码实现了一个计算输入数字的阶乘的程序。它通过循环和数组来进行阶乘的计算,并打印出结果。程序还包含输入验证,确保用户输入的数字是非负的。
回文数
/** * @file * @brief Program to identify if a number is [palindrome * number](https://en.wikipedia.org/wiki/Palindrome) or not. * @see project_euler/problem_4/sol1.c */ #include <assert.h> #include <stdbool.h> #include <stdio.h> bool isPalindrome(int number); /** Driver Code */ int main() { assert(isPalindrome(0)); assert(isPalindrome(1)); assert(isPalindrome(12321)); assert(!isPalindrome(1234)); return 0; } /** * Check given number whether is palindrome number or not * @param number number to check * @return `true` if given number is palindrome number * @return `false` if number is not a palindrome number */ bool isPalindrome(int number) { int reversedNumber = 0; int originalNumber = number; while (number != 0) { int remainder = number % 10; reversedNumber = reversedNumber * 10 + remainder; number /= 10; } return originalNumber == reversedNumber; }
这段代码是一个用于判断一个数字是否是回文数的程序。下面是代码的详细解释:
- 首先,包含了一些头文件(assert.h, stdbool.h, stdio.h),用于引入所需的函数和变量类型。
- 接下来定义了一个函数
isPalindrome
,用于判断给定的数字是否是回文数。该函数接受一个整数参数number
,并返回一个布尔值。 - 在
isPalindrome
函数内部,定义了两个整型变量reversedNumber
和originalNumber
,分别用于保存数字的反转结果和原始数字。 - 使用一个循环,不断地取给定数字
number
的最后一位,并将其添加到reversedNumber
的末尾,直到number
变为0。 - 在每次迭代中,首先将
number
对10取余得到最后一位数字remainder
,然后将reversedNumber
乘以10并加上remainder
,实现将最后一位数字添加到reversedNumber
的末尾。 - 最后,将
number
除以10,实现去掉最后一位数字。 - 完成循环后,
reversedNumber
即为数字的反转结果。 - 最后,比较
originalNumber
和reversedNumber
是否相等,如果相等,则说明给定数字是回文数,返回true
,否则返回false
。 - 在
main
函数中,使用assert
宏来检查isPalindrome
函数的结果是否符合预期。分别传入一些测试用例,包括0、1、12321和1234。 - 程序通过返回0来表示执行成功,并终止程序的执行。
因此,这段代码实现了一个判断给定数字是否是回文数的函数,并在main
函数中进行了测试。它通过将数字进行反转并与原始数字进行比较,来确定是否是回文数。
/** * @file * @brief Functions related to 3D quaternions and Euler angles. * @author Krishna Vedala */ #include <stdio.h> #ifdef __arm__ // if compiling for ARM-Cortex processors #define LIBQUAT_ARM #include <arm_math.h> #else #include <math.h> #endif #include <assert.h> #include "geometry_datatypes.h" /** * @addtogroup quats 3D Quaternion operations * @{ */ /** * Function to convert given Euler angles to a quaternion. * \f{eqnarray*}{ * q_{0} & = * &\cos\left(\frac{\phi}{2}\right)\cos\left(\frac{\theta}{2}\right)\cos\left(\frac{\psi}{2}\right) * + * \sin\left(\frac{\phi}{2}\right)\sin\left(\frac{\theta}{2}\right)\sin\left(\frac{\psi}{2}\right)\\ * q_{1} & = * &\sin\left(\frac{\phi}{2}\right)\cos\left(\frac{\theta}{2}\right)\cos\left(\frac{\psi}{2}\right) * - * \cos\left(\frac{\phi}{2}\right)\sin\left(\frac{\theta}{2}\right)\sin\left(\frac{\psi}{2}\right)\\ * q_{2} & = * &\cos\left(\frac{\phi}{2}\right)\sin\left(\frac{\theta}{2}\right)\cos\left(\frac{\psi}{2}\right) * + * \sin\left(\frac{\phi}{2}\right)\cos\left(\frac{\theta}{2}\right)\sin\left(\frac{\psi}{2}\right)\\ * q_{3} & = * &\cos\left(\frac{\phi}{2}\right)\cos\left(\frac{\theta}{2}\right)\sin\left(\frac{\psi}{2}\right) * - * \sin\left(\frac{\phi}{2}\right)\sin\left(\frac{\theta}{2}\right)\cos\left(\frac{\psi}{2}\right)\\ * \f} * * @param [in] in_euler input Euler angles instance * @returns converted quaternion */ quaternion quat_from_euler(const euler *in_euler) { quaternion out_quat; if (!in_euler) // if null { fprintf(stderr, "%s: Invalid input.", __func__); return out_quat; } quaternion temp; float cy = cosf(in_euler->yaw * 0.5f); float sy = sinf(in_euler->yaw * 0.5f); float cp = cosf(in_euler->pitch * 0.5f); float sp = sinf(in_euler->pitch * 0.5f); float cr = cosf(in_euler->roll * 0.5f); float sr = sinf(in_euler->roll * 0.5f); temp.w = cr * cp * cy + sr * sp * sy; temp.q1 = sr * cp * cy - cr * sp * sy; temp.q2 = cr * sp * cy + sr * cp * sy; temp.q3 = cr * cp * sy - sr * sp * cy; return temp; } /** * Function to convert given quaternion to Euler angles. * \f{eqnarray*}{ * \phi & = & * \tan^{-1}\left[\frac{2\left(q_0q_1+q_2q_3\right)}{1-2\left(q_1^2+q_2^2\right)}\right]\\ * \theta & = * &-\sin^{-1}\left[2\left(q_0q_2-q_3q_1\right)\right]\\ * \psi & = & * \tan^{-1}\left[\frac{2\left(q_0q_3+q_1q_2\right)}{1-2\left(q_2^2+q_3^2\right)}\right]\\ * \f} * * @param [in] in_quat input quaternion instance * @returns converted euler angles */ euler euler_from_quat(const quaternion *in_quat) { euler out_euler; if (!in_quat) // if null { fprintf(stderr, "%s: Invalid input.", __func__); return out_euler; } out_euler.roll = atan2f( 2.f * (in_quat->w * in_quat->q1 + in_quat->q2 * in_quat->q3), 1.f - 2.f * (in_quat->q1 * in_quat->q1 + in_quat->q2 * in_quat->q2)); out_euler.pitch = asinf(2.f * (in_quat->w * in_quat->q2 + in_quat->q1 * in_quat->q3)); out_euler.yaw = atan2f( 2.f * (in_quat->w * in_quat->q3 + in_quat->q1 * in_quat->q2), 1.f - 2.f * (in_quat->q2 * in_quat->q2 + in_quat->q3 * in_quat->q3)); return out_euler; } /** * Function to multiply two quaternions. * \f{eqnarray*}{ * \mathbf{c} & = & \mathbf{a}\otimes\mathbf{b}\\ * & = & \begin{bmatrix}a_{0} & a_{1} & a_{2} & * a_{3}\end{bmatrix}\otimes\begin{bmatrix}b_{0} & b_{1} & b_{2} & * b_{3}\end{bmatrix}\\ * & = & * \begin{bmatrix} * a_{0}b_{0}-a_{1}b_{1}-a_{2}b_{2}-a_{3}b_{3}\\ * a_{0}b_{1}+a_{1}b_{0}+a_{2}b_{3}-a_{3}b_{2}\\ * a_{0}b_{2}-a_{1}b_{3}+a_{2}b_{0}+a_{3}b_{1}\\ * a_{0}b_{3}+a_{1}b_{2}-a_{2}b_{1}+a_{3}b_{0} * \end{bmatrix}^{T} * \f} * * @param [in] in_quat1 first input quaternion instance * @param [in] in_quat2 second input quaternion instance * @returns resultant quaternion */ quaternion quaternion_multiply(const quaternion *in_quat1, const quaternion *in_quat2) { quaternion out_quat; if (!in_quat1 || !in_quat2) // if null { fprintf(stderr, "%s: Invalid input.", __func__); return out_quat; } out_quat.w = in_quat1->w * in_quat2->w - in_quat1->q1 * in_quat2->q1 - in_quat1->q2 * in_quat2->q2 - in_quat1->q3 * in_quat2->q3; out_quat.q1 = in_quat1->w * in_quat2->q1 + in_quat1->q1 * in_quat2->w + in_quat1->q2 * in_quat2->q3 - in_quat1->q3 * in_quat2->q2; out_quat.q2 = in_quat1->w * in_quat2->q2 - in_quat1->q1 * in_quat2->q3 + in_quat1->q2 * in_quat2->w + in_quat1->q3 * in_quat2->q1; out_quat.q3 = in_quat1->w * in_quat2->q3 + in_quat1->q1 * in_quat2->q2 - in_quat1->q2 * in_quat2->q1 + in_quat1->q3 * in_quat2->w; return out_quat; } /** @} */ static void test() { quaternion quat = {0.7071f, 0.7071f, 0.f, 0.f}; euler eul = euler_from_quat(&quat); printf("Euler: %.4g, %.4g, %.4g\n", eul.pitch, eul.roll, eul.yaw); quaternion test_quat = quat_from_euler(&eul); printf("Quaternion: %.4g %+.4g %+.4g %+.4g\n", test_quat.w, test_quat.dual.x, test_quat.dual.y, test_quat.dual.z); assert(fabsf(test_quat.w - quat.w) < .01); assert(fabsf(test_quat.q1 - quat.q1) < .01); assert(fabsf(test_quat.q2 - quat.q2) < .01); assert(fabsf(test_quat.q3 - quat.q3) < .01); } int main() { test(); return 0; }
这段代码是关于3D四元数和欧拉角的操作。它包含了以下几个函数:
quat_from_euler()
:将给定的欧拉角转换为四元数。euler_from_quat()
:将给定的四元数转换为欧拉角。quaternion_multiply()
:将两个四元数相乘,得到结果四元数。
在代码的末尾,还有一个test()
函数用于测试这些函数的正确性,并进行了一些断言来验证结果。
你可以将这段代码保存为一个C文件,并通过编译器进行编译和运行。在运行过程中,它会输出欧拉角和四元数的值,并进行断言验证。如果断言通过,即表示函数运行正确。
请注意,这是一个简化的示例代码,并且依赖于一些其他文件(例如geometry_datatypes.h
)。如果你想完整地运行这段代码,需要确保所有的依赖项都已经包含并正确设置。
这段代码是用来进行3D姿态表示的转换操作的。它实现了将欧拉角转换为四元数,以及将四元数转换为欧拉角的功能。
在计算机图形学和机器人学中,姿态表示是描述物体或者机器人在三维空间中的方向和位置的一种方式。欧拉角是一种常见的姿态表示方法,通过三个角度(通常是滚转、俯仰和偏航)来描述物体的旋转。而四元数是一种更高效和稳定的姿态表示方法,可以用四个实数来表示旋转。
这段代码提供了欧拉角和四元数之间的转换功能,可以在不同的姿态表示之间进行转换。通过这些转换函数,你可以将一个欧拉角表示的姿态转换为对应的四元数表示,或者将一个四元数表示的姿态转换为对应的欧拉角表示。
这些转换操作在计算机图形学、机器人学、虚拟现实等领域都有广泛的应用。它们可以用于物体的旋转和姿态插值,机器人的控制和路径规划,以及许多其他需要处理三维姿态的应用场景。
c++与密码学
# If necessary, use the RELATIVE flag, otherwise each source file may be listed # with full pathname. The RELATIVE flag makes it easier to extract an executable's name # automatically. file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.c ) foreach( testsourcefile ${APP_SOURCES} ) string( REPLACE ".c" "" testname ${testsourcefile} ) # File type. Example: `.c` add_executable( ${testname} ${testsourcefile} ) if(OpenMP_C_FOUND) target_link_libraries(${testname} OpenMP::OpenMP_C) endif() if(MATH_LIBRARY) target_link_libraries(${testname} ${MATH_LIBRARY}) endif() install(TARGETS ${testname} DESTINATION "bin/cipher") # Folder name. Do NOT include `<>` endforeach( testsourcefile ${APP_SOURCES} )
这是一个CMakeLists.txt文件中的一段代码,用于自动化构建多个可执行文件,并将它们安装到指定的目录。
首先,通过使用"file(GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.c)“命令,找到当前源代码目录下所有以”.c"为扩展名的源文件,并将它们作为列表存储在变量APP_SOURCES中。RELATIVE标志将源文件的路径相对于当前源代码目录进行存储,方便后续使用。
然后,通过foreach循环,遍历APP_SOURCES列表中的每个源文件名(testsourcefile)。在循环中,首先通过"string(REPLACE “.c” “” testname ${testsourcefile})“命令,将testsourcefile中的”.c"替换为空字符串,得到一个不包含扩展名的文件名(testname)。
接下来,使用"add_executable(${testname} ${testsourcefile})"命令,根据源文件名生成一个可执行文件,并将该文件添加到构建系统中。
然后,根据条件判断,如果OpenMP库可用,使用"target_link_libraries(t e s t n a m e O p e n M P : : O p e n M P C ) " 命令,将 O p e n M P 库链接到可执行文件中。如果定义了 M A T H L I B R A R Y 变量,使用 " t a r g e t l i n k l i b r a r i e s ( {testname} OpenMP::OpenMP_C)"命令,将OpenMP库链接到可执行文件中。如果定义了MATH_LIBRARY变量,使用"target_link_libraries(testnameOpenMP::OpenMPC)"命令,将OpenMP库链接到可执行文件中。如果定义了MATHLIBRARY变量,使用"targetlinklibraries({testname} ${MATH_LIBRARY})"命令,将其它的数学库链接到可执行文件中。
最后,使用"install(TARGETS ${testname} DESTINATION “bin/cipher”)"命令,将生成的可执行文件安装到目标目录"bin/cipher"中。
整个循环结束后,所有的源文件都被编译为对应的可执行文件,并安装到指定目录中。
/** * @file * @brief An [affine cipher](https://en.wikipedia.org/wiki/Affine_cipher) is a * letter substitution cipher that uses a linear transformation to substitute * letters in a message. * @details Given an alphabet of length M with characters with numeric values * 0-(M-1), an arbitrary character x can be transformed with the expression (ax * + b) % M into our ciphertext character. The only caveat is that a must be * relatively prime with M in order for this transformation to be invertible, * i.e., gcd(a, M) = 1. * @author [Daniel Murrow](https://github.com/dsmurrow) */ #include <assert.h> /// for assertions #include <stdio.h> /// for IO #include <stdlib.h> /// for div function and div_t struct as well as malloc and free #include <string.h> /// for strlen, strcpy, and strcmp /** * @brief number of characters in our alphabet (printable ASCII characters) */ #define ALPHABET_SIZE 95 /** * @brief used to convert a printable byte (32 to 126) to an element of the * group Z_95 (0 to 94) */ #define Z95_CONVERSION_CONSTANT 32 /** * @brief a structure representing an affine cipher key */ typedef struct { int a; ///< what the character is being multiplied by int b; ///< what is being added after the multiplication with `a` } affine_key_t; /** * @brief finds the value x such that (a * x) % m = 1 * * @param a number we are finding the inverse for * @param m the modulus the inversion is based on * * @returns the modular multiplicative inverse of `a` mod `m` */ int modular_multiplicative_inverse(unsigned int a, unsigned int m) { int x[2] = {1, 0}; div_t div_result; if (m == 0) { return 0; } a %= m; if (a == 0) { return 0; } div_result.rem = a; while (div_result.rem > 0) { div_result = div(m, a); m = a; a = div_result.rem; // Calculate value of x for this iteration int next = x[1] - (x[0] * div_result.quot); x[1] = x[0]; x[0] = next; } return x[1]; } /** * @brief Given a valid affine cipher key, this function will produce the * inverse key. * * @param key They key to be inverted * * @returns inverse of key */ affine_key_t inverse_key(affine_key_t key) { affine_key_t inverse; inverse.a = modular_multiplicative_inverse(key.a, ALPHABET_SIZE); // Turn negative results positive inverse.a += ALPHABET_SIZE; inverse.a %= ALPHABET_SIZE; inverse.b = -(key.b % ALPHABET_SIZE) + ALPHABET_SIZE; return inverse; } /** * @brief Encrypts character string `s` with key * * @param s string to be encrypted * @param key affine key used for encryption * * @returns void */ void affine_encrypt(char *s, affine_key_t key) { for (int i = 0; s[i] != '\0'; i++) { int c = (int)s[i] - Z95_CONVERSION_CONSTANT; c *= key.a; c += key.b; c %= ALPHABET_SIZE; s[i] = (char)(c + Z95_CONVERSION_CONSTANT); } } /** * @brief Decrypts an affine ciphertext * * @param s string to be decrypted * @param key Key used when s was encrypted * * @returns void */ void affine_decrypt(char *s, affine_key_t key) { affine_key_t inverse = inverse_key(key); for (int i = 0; s[i] != '\0'; i++) { int c = (int)s[i] - Z95_CONVERSION_CONSTANT; c += inverse.b; c *= inverse.a; c %= ALPHABET_SIZE; s[i] = (char)(c + Z95_CONVERSION_CONSTANT); } } /** * @brief Tests a given string * * @param s string to be tested * @param a value of key.a * @param b value of key.b * * @returns void */ void test_string(const char *s, const char *ciphertext, int a, int b) { char *copy = malloc((strlen(s) + 1) * sizeof(char)); strcpy(copy, s); affine_key_t key = {a, b}; affine_encrypt(copy, key); assert(strcmp(copy, ciphertext) == 0); // assert that the encryption worked affine_decrypt(copy, key); assert(strcmp(copy, s) == 0); // assert that we got the same string we started with free(copy); } /** * @brief Test multiple strings * * @returns void */ static void tests() { test_string("Hello!", "&3ddy2", 7, 11); test_string("TheAlgorithms/C", "DNC}=jHS2zN!7;E", 67, 67); test_string("0123456789", "840,($ {ws", 91, 88); test_string("7W@;cdeRT9uL", "JDfa*we?z&bL", 77, 76); test_string("~Qr%^-+++$leM", "r'qC0$sss;Ahf", 8, 90); test_string("The quick brown fox jumps over the lazy dog", "K7: .*6<4 =-0(1 90' 5*2/, 0):- +7: 3>%& ;08", 94, 0); test_string( "One-1, Two-2, Three-3, Four-4, Five-5, Six-6, Seven-7, Eight-8, " "Nine-9, Ten-10", "H&60>\\2*uY0q\\2*p4660E\\2XYn40x\\2XDB60L\\2VDI0 " "\\2V6B6&0S\\2%D=p;0'\\2tD&60Z\\2*6&0>j", 51, 18); printf("All tests have successfully passed!\n"); } /** * @brief main function * * @returns 0 upon successful program exit */ int main() { tests(); return 0; }
这段代码实现了一个仿射密码(Affine Cipher),它是一种使用线性变换来替换消息中的字母的字母替换密码。
代码中定义了一个结构体 affine_key_t
,表示仿射密码的密钥,包括两个整数 a
和 b
。函数 modular_multiplicative_inverse
用于找到关于模 m
的数 x
,使得 (a * x) % m = 1
,即计算模乘法逆元。函数 inverse_key
则用于计算给定密钥的逆密钥。
affine_encrypt
函数用于对字符串进行加密,它将字符串中的每个字符转换成相应的仿射密码字符。affine_decrypt
函数用于对仿射密码进行解密,恢复原始字符串。
测试部分的函数 test_string
用于对给定的字符串进行加密和解密,并进行断言检查是否得到了正确的结果。最后的 tests
函数用于调用 test_string
函数进行多个字符串的测试。
主函数 main
中调用了 tests
函数进行测试,并输出测试结果。
这段代码通过对字符串进行加密和解密的测试来验证仿射密码的实现是否正确。下面是代码中的几个样例测试:
- 输入字符串:“Hello!”,密钥参数:a=7,b=11。
预期输出密文:“&3ddy2”,解密后得到原始字符串:“Hello!” - 输入字符串:“TheAlgorithms/C”,密钥参数:a=67,b=67。
预期输出密文:“DNC}=jHS2zN!7;E”,解密后得到原始字符串:“TheAlgorithms/C” - 输入字符串:“0123456789”,密钥参数:a=91,b=88。
预期输出密文:“840,($ {ws”,解密后得到原始字符串:“0123456789” - 输入字符串:“7W@;cdeRT9uL”,密钥参数:a=77,b=76。
预期输出密文:“JDfa*we?z&bL”,解密后得到原始字符串:“7W@;cdeRT9uL” - 输入字符串:“~Qr%^-+++l e M " ,密钥参数: a = 8 , b = 90 。预期输出密文: " r ′ q C 0 leM",密钥参数:a=8,b=90。 预期输出密文:"r'qC0leM",密钥参数:a=8,b=90。预期输出密文:"r′qC0sss;Ahf”,解密后得到原始字符串:“~Qr%^-+++$leM”
- 输入字符串:“The quick brown fox jumps over the lazy dog”,密钥参数:a=94,b=0。
预期输出密文:“K7: .6<4 =-0(1 90’ 52/, 0):- +7: 3>%& ;08”,解密后得到原始字符串:“The quick brown fox jumps over the lazy dog” - 输入字符串:“One-1, Two-2, Three-3, Four-4, Five-5, Six-6, Seven-7, Eight-8, Nine-9, Ten-10”,密钥参数:a=51,b=18。
预期输出密文:“H&60>\2uY0q\2p4660E\2XYn40x\2XDB60L\2VDI0 \2V6B6&0S\2%D=p;0’\2tD&60Z\2*6&0>j”,解密后得到原始字符串:“One-1, Two-2, Three-3, Four-4, Five-5, Six-6, Seven-7, Eight-8, Nine-9, Ten-10”
如果代码实现正确,所有样例测试应该通过并输出 “All tests have successfully passed!” 的提示信息。您可以在自己的开发环境中运行代码,观察输出结果是否符合预期。
/** * @file * @brief [ROT13](https://en.wikipedia.org/wiki/ROT13) is a simple letter * substitution cipher that replaces a letter with the 13th letter after it in * the alphabet. * @details ROT13 transforms a piece of text by examining its alphabetic * characters and replacing each one with the letter 13 places further along in * the alphabet, wrapping back to the beginning if necessary. A becomes N, B * becomes O, and so on up to M, which becomes Z, then the sequence continues at * the beginning of the alphabet: N becomes A, O becomes B, and so on to Z, * which becomes M. * @author [Jeremias Moreira Gomes](https://github.com/j3r3mias) */ #include <stdio.h> /// for IO operations #include <string.h> /// for string operations #include <assert.h> /// for assert /** * @brief Apply the ROT13 cipher * @param s contains the string to be processed */ void rot13(char *s) { for (int i = 0; s[i]; i++) { if (s[i] >= 'A' && s[i] <= 'Z') { s[i] = 'A' + ((s[i] - 'A' + 13) % 26); } else if (s[i] >= 'a' && s[i] <= 'z') { s[i] = 'a' + ((s[i] - 'a' + 13) % 26); } } } /** * @brief Self-test implementations * @returns void */ static void test() { char test_01[] = "The more I C, the less I see."; rot13(test_01); assert(strcmp(test_01, "Gur zber V P, gur yrff V frr.") == 0); char test_02[] = "Which witch switched the Swiss wristwatches?"; rot13(test_02); assert(strcmp(test_02, "Juvpu jvgpu fjvgpurq gur Fjvff jevfgjngpurf?") == 0); char test_03[] = "Juvpu jvgpu fjvgpurq gur Fjvff jevfgjngpurf?"; rot13(test_03); assert(strcmp(test_03, "Which witch switched the Swiss wristwatches?") == 0); printf("All tests have successfully passed!\n"); } /** * @brief Main function * @returns 0 on exit */ int main() { test(); // run self-test implementations return 0; }
这段代码实现了 ROT13(ROT13)密码,它是一种简单的字母替换密码,将字母替换为字母表中后面第 13 个字母。
代码中的 rot13
函数用于应用 ROT13 密码。它遍历字符串中的每个字符,如果字符是大写字母,则将其替换为字母表中后面第 13 个字母(如果需要则回到字母表开头);如果字符是小写字母,则同样将其替换为后面第 13 个字母。该函数会原地修改输入的字符串。
代码中的 test
函数用于自我测试实现是否正确。它执行了几个样例测试,通过比较加密和解密后的字符串与预期结果来验证实现的正确性。如果所有测试都通过,则输出 “All tests have successfully passed!” 的提示信息。
代码中的测试样例如下所示:
- 输入字符串:“The more I C, the less I see.”
预期输出结果:“Gur zber V P, gur yrff V frr.” - 输入字符串:“Which witch switched the Swiss wristwatches?”
预期输出结果:“Juvpu jvgpu fjvgpurq gur Fjvff jevfgjngpurf?” - 输入字符串:“Juvpu jvgpu fjvgpurq gur Fjvff jevfgjngpurf?”
预期输出结果:“Which witch switched the Swiss wristwatches?”
如果代码实现正确,所有测试应该通过,并输出 “All tests have successfully passed!” 的提示信息。
您可以在自己的开发环境中运行代码,观察输出结果是否符合预期。
/** * @file * @brief Functions related to 3D vector operations. * @author Krishna Vedala */ #include <stdio.h> #ifdef __arm__ // if compiling for ARM-Cortex processors #define LIBQUAT_ARM #include <arm_math.h> #else #include <math.h> #endif #include <assert.h> #include "geometry_datatypes.h" /** * @addtogroup vec_3d 3D Vector operations * @{ */ /** * Subtract one vector from another. @f[ * \vec{c}=\vec{a}-\vec{b}=\left(a_x-b_x\right)\hat{i}+ * \left(a_y-b_y\right)\hat{j}+\left(a_z-b_z\right)\hat{k}@f] * @param[in] a vector to subtract from * @param[in] b vector to subtract * @returns resultant vector */ vec_3d vector_sub(const vec_3d *a, const vec_3d *b) { vec_3d out; #ifdef LIBQUAT_ARM arm_sub_f32((float *)a, (float *)b, (float *)&out); #else out.x = a->x - b->x; out.y = a->y - b->y; out.z = a->z - b->z; #endif return out; } /** * Add one vector to another. @f[ * \vec{c}=\vec{a}+\vec{b}=\left(a_x+b_x\right)\hat{i}+ * \left(a_y+b_y\right)\hat{j}+\left(a_z+b_z\right)\hat{k}@f] * @param[in] a vector to add to * @param[in] b vector to add * @returns resultant vector */ vec_3d vector_add(const vec_3d *a, const vec_3d *b) { vec_3d out; #ifdef LIBQUAT_ARM arm_add_f32((float *)a, (float *)b, (float *)&out); #else out.x = a->x + b->x; out.y = a->y + b->y; out.z = a->z + b->z; #endif return out; } /** * Obtain the dot product of two 3D vectors. * @f[ * \vec{a}\cdot\vec{b}=a_xb_x + a_yb_y + a_zb_z * @f] * @param[in] a first vector * @param[in] b second vector * @returns resulting dot product */ float dot_prod(const vec_3d *a, const vec_3d *b) { float dot; #ifdef LIBQUAT_ARM arm_dot_prod_f32((float *)a, (float *)b, &dot); #else dot = a->x * b->x; dot += a->y * b->y; dot += a->z * b->z; #endif return dot; } /** * Compute the vector product of two 3d vectors. * @f[\begin{align*} * \vec{a}\times\vec{b} &= \begin{vmatrix} * \hat{i} & \hat{j} & \hat{k}\\ * a_x & a_y & a_z\\ * b_x & b_y & b_z * \end{vmatrix}\\ * &= \left(a_yb_z-b_ya_z\right)\hat{i} - \left(a_xb_z-b_xa_z\right)\hat{j} * + \left(a_xb_y-b_xa_y\right)\hat{k} \end{align*} * @f] * @param[in] a first vector @f$\vec{a}@f$ * @param[in] b second vector @f$\vec{b}@f$ * @returns resultant vector @f$\vec{o}=\vec{a}\times\vec{b}@f$ */ vec_3d vector_prod(const vec_3d *a, const vec_3d *b) { vec_3d out; // better this way to avoid copying results to input // vectors themselves out.x = a->y * b->z - a->z * b->y; out.y = -a->x * b->z + a->z * b->x; out.z = a->x * b->y - a->y * b->x; return out; } /** * Print formatted vector on stdout. * @param[in] a vector to print * @param[in] name name of the vector * @returns string representation of vector */ const char *print_vector(const vec_3d *a, const char *name) { static char vec_str[100]; // static to ensure the string life extends the // life of function snprintf(vec_str, 99, "vec(%s) = (%.3g)i + (%.3g)j + (%.3g)k\n", name, a->x, a->y, a->z); return vec_str; } /** * Compute the norm a vector. * @f[\lVert\vec{a}\rVert = \sqrt{\vec{a}\cdot\vec{a}} @f] * @param[in] a input vector * @returns norm of the given vector */ float vector_norm(const vec_3d *a) { float n = dot_prod(a, a); #ifdef LIBQUAT_ARM arm_sqrt_f32(*n, n); #else n = sqrtf(n); #endif return n; } /** * Obtain unit vector in the same direction as given vector. * @f[\hat{a}=\frac{\vec{a}}{\lVert\vec{a}\rVert}@f] * @param[in] a input vector * @returns n unit vector in the direction of @f$\vec{a}@f$ */ vec_3d unit_vec(const vec_3d *a) { vec_3d n = {0}; float norm = vector_norm(a); if (fabsf(norm) < EPSILON) { // detect possible divide by 0 return n; } if (norm != 1.F) // perform division only if needed { n.x = a->x / norm; n.y = a->y / norm; n.z = a->z / norm; } return n; } /** * The cross product of vectors can be represented as a matrix * multiplication operation. This function obtains the `3x3` matrix * of the cross-product operator from the first vector. * @f[\begin{align*} * \left(\vec{a}\times\right)\vec{b} &= \tilde{A}_a\vec{b}\\ * \tilde{A}_a &= * \begin{bmatrix}0&-a_z&a_y\\a_z&0&-a_x\\-a_y&a_x&0\end{bmatrix} * \end{align*}@f] * @param[in] a input vector * @returns the `3x3` matrix for the cross product operator * @f$\left(\vec{a}\times\right)@f$ */ mat_3x3 get_cross_matrix(const vec_3d *a) { mat_3x3 A = {0., -a->z, a->y, a->z, 0., -a->x, -a->y, a->x, 0.}; return A; } /** * Obtain the angle between two given vectors. * @f[\alpha=acos\left(\frac{\vec{a} \cdot \vec{b}}{\lVert\vec{a}\rVert \cdot \lVert\vec{b}\rVert}\right)@f] * @param[in] a first input vector * @param[in] b second input vector * @returns angle between @f$\vec{a}@f$ and @f$\vec{b}@f$ in radians */ double get_angle(const vec_3d *a, const vec_3d *b) { double alpha, cos_alpha; float norm_a = vector_norm(a); ///< The norm of vector a float norm_b = vector_norm(b); ///< The norm of vector b if (fabsf(norm_a) < EPSILON || fabsf(norm_b) < EPSILON) /// detect possible division by 0 - the angle is not defined in this case { return NAN; } cos_alpha = dot_prod(a, b) / (norm_a * norm_b); alpha = acos(cos_alpha); // delivers the radian return alpha; // in range from -1 to 1 } /** @} */ /** * @brief Testing function * @returns `void` */ static void test() { vec_3d a = {1., 2., 3.}; vec_3d b = {1., 1., 1.}; float d; // printf("%s", print_vector(&a, "a")); // printf("%s", print_vector(&b, "b")); d = vector_norm(&a); // printf("|a| = %.4g\n", d); assert(fabsf(d - 3.742f) < 0.01); d = vector_norm(&b); // printf("|b| = %.4g\n", d); assert(fabsf(d - 1.732f) < 0.01); d = dot_prod(&a, &b); // printf("Dot product: %f\n", d); assert(fabsf(d - 6.f) < 0.01); vec_3d c = vector_prod(&a, &b); // printf("Vector product "); // printf("%s", print_vector(&c, "c")); assert(fabsf(c.x - (-1.f)) < 0.01); assert(fabsf(c.y - (2.f)) < 0.01); assert(fabsf(c.z - (-1.f)) < 0.01); double alpha = get_angle(&a, &b); // printf("The angle is %f\n", alpha); assert(fabsf(alpha - 0.387597) < 0.01); } /** * @brief Main function * * @return 0 on exit */ int main(void) { test(); return 0; }
这是一个关于3D向量操作的函数集,用于进行向量的加减、点积、叉积、范数、单位化等操作。这些函数封装了对不同硬件平台(包括ARM处理器)的适配,并包含了一些简单的测试用例。
这些函数可以用于处理和操作3D空间中的向量,例如在计算机图形学、物理模拟、机器人学等领域中。通过这些函数,你可以进行向量的加减、点积和叉积运算,计算向量的范数(长度),以及将向量单位化为单位向量。
在代码的末尾,有一个test()
函数用于测试这些函数的正确性,并进行了一些断言来验证结果。你可以运行这段代码来执行测试,并检查断言的结果是否为真。如果断言通过,则表示函数的实现是正确的。
你可以将这段代码保存为一个C文件,并通过编译器进行编译和运行。在运行过程中,它会输出一些测试结果,并进行断言验证。如果断言通过,即表示函数实现正确,否则可能需要检查代码实现中的错误。