保存时间:2026/4/2 12:12:52
#include <iostream>
#include <Eigen/Dense>
int main() {
// 定义一个方阵
Eigen::MatrixXd A = Eigen::MatrixXd::Random(3, 3);
// 进行奇异值分解
Eigen::JacobiSVD<Eigen::MatrixXd> svd(A, Eigen::ComputeFullU | Eigen::ComputeFullV);
// 构造“解矩阵”B
Eigen::MatrixXd B = svd.matrixV() * Eigen::MatrixXd::Zero(3, 3) * svd.matrixU().transpose();
// 输出结果
std::cout << "矩阵A: \n" << A << std::endl;
std::cout << "解矩阵B: \n" << B << std::endl;
return 0;
}
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/core/eigen.hpp>
#include <opencv2/imgproc.hpp>
int main() {
// 定义一个方阵
cv::Mat A = cv::Mat::randn(cv::Size(3, 3), 0, 1);
// 进行奇异值分解
cv::Mat U, V;
cv::Mat w;
cv::SVD::compute(A, w, U, V);
// 构造“解矩阵”B
cv::Mat B = V * cv::Mat::zeros(3, 3, CV_64F) * U.t();
// 输出结果
std::cout << "矩阵A: \n" << A << std::endl;
std::cout << "解矩阵B: \n" << B << std::endl;
return 0;
}
#include <iostream>
#include <Eigen/Dense>
int main() {
// 定义一个 3x3 的方阵
Eigen::Matrix3d A;
A << 1, 2, 3,
4, 5, 6,
7, 8, 9;
// 检查矩阵是否可逆
if (A.determinant() != 0) {
// 计算逆矩阵
Eigen::Matrix3d A_inv = A.inverse();
// 输出逆矩阵
std::cout << "矩阵 A 的逆矩阵: \n" << A_inv << std::endl;
} else {
std::cout << "矩阵 A 不可逆" << std::endl;
}
return 0;
}
#include <iostream>
#include <opencv2/core.hpp>
int main() {
// 定义一个 3x3 的方阵
cv::Mat A = cv::Mat::ones(3, 3, CV_64F);
A.at<double>(0, 0) = 1; A.at<double>(0, 1) = 2; A.at<double>(0, 2) = 3;
A.at<double>(1, 0) = 4; A.at<double>(1, 1) = 5; A.at<double>(1, 2) = 6;
A.at<double>(2, 0) = 7; A.at<double>(2, 1) = 8; A.at<double>(2, 2) = 9;
// 计算逆矩阵
cv::Mat A_inv;
int result = A.inv(A_inv);
if (result == cv::NO_ERR) {
// 输出逆矩阵
std::cout << "矩阵 A 的逆矩阵: \n" << A_inv << std::endl;
} else {
std::cout << "矩阵 A 不可逆" << std::endl;
}
return 0;
}
inverse() 函数计算逆矩阵,在计算之前通过 determinant() 函数检查矩阵的行列式是否为零来判断矩阵是否可逆。OpenCV 库使用 inv() 函数计算逆矩阵,函数返回值为 cv::NO_ERR 时表示计算成功,否则表示矩阵不可逆。llama.cpp 中从输入文本获取 token 并进行一些基本处理的大致过程(实际 llama.cpp 代码复杂得多,这里只是示意)。#include <iostream>
#include <vector>
#include <string>
#include "llama.h" // 假设包含llama相关的头文件
// 模拟分词函数,这里只是简单示例,实际会复杂很多
std::vector<llama_token> tokenize(const std::string& input_text, const llama_model& model) {
std::vector<llama_token> tokens;
// 实际中调用llama.cpp中的分词逻辑
// 这里只是简单将每个字符作为一个token处理(错误示范,仅为展示流程)
for (char c : input_text) {
// 实际需要通过模型的词表映射为真正的token
llama_token token = static_cast<llama_token>(c);
tokens.push_back(token);
}
return tokens;
}
int main() {
// 加载模型,这里只是示例代码,实际需要正确的模型路径和参数
llama_model model = llama_load_model_from_file("path/to/your/model.bin");
if (model == nullptr) {
std::cerr << "Failed to load model" << std::endl;
return 1;
}
std::string input_text = "Hello, world!";
std::vector<llama_token> tokens = tokenize(input_text, model);
// 这里可以对token序列进行进一步处理,如添加位置编码等
// 实际在llama.cpp中会有更复杂的逻辑
// 释放模型资源
llama_free_model(model);
return 0;
}
llama_load_model_from_file 函数只是示例,实际调用需要传入正确的模型文件路径等参数。tokenize 函数只是简单模拟,真正的分词逻辑在 llama.cpp 中会基于模型的词表进行复杂处理。llama.cpp 代码包含大量的优化和细节处理。llama.cpp 项目中,分词(tokenizer)相关的代码实现有一定复杂性,且依赖于项目中的其他结构和函数。以下是从 llama.cpp 项目中提取出的简化且关键部分的分词函数(tokenize 相关逻辑)示例,以帮助你理解大致原理(实际代码会更复杂且有更多细节处理,这里只是核心逻辑展示,且为了便于理解做了适当注释和简化):#include <cstring>
#include <vector>
#include <string>
#include <unordered_map>
// 假设这是存储词表的结构,实际在项目中会从模型文件等加载
// 这里简单模拟,键是token字符串,值是对应的token ID
std::unordered_map<std::string, int> tokenizer_vocab = {
{"<unk>", 0},
{"<s>", 1},
{"</s>", 2},
{"hello", 3},
{"world", 4},
// 这里可以添加更多实际词表内容
};
// 简单的分词函数,将输入文本按空格等简单分割并映射为token ID
std::vector<int> tokenize(const std::string& input_text) {
std::vector<int> tokens;
char *str_copy = new char[input_text.size() + 1];
std::strcpy(str_copy, input_text.c_str());
char *token = std::strtok(str_copy, " \t\n");
while (token != nullptr) {
std::string token_str(token);
// 尝试在词表中查找token
auto it = tokenizer_vocab.find(token_str);
if (it != tokenizer_vocab.end()) {
tokens.push_back(it->second);
} else {
// 如果找不到,使用未知token ID(这里假设为0)
tokens.push_back(0);
}
token = std::strtok(nullptr, " \t\n");
}
delete[] str_copy;
return tokens;
}
int main() {
std::string input = "hello world";
std::vector<int> result_tokens = tokenize(input);
for (int token : result_tokens) {
std::cout << token << " ";
}
std::cout << std::endl;
return 0;
}
tokenizer_vocab 模拟了词表,存储了一些简单的 token 及其对应的 ID。tokenize 函数将输入文本按空格等进行分割,然后在词表中查找每个分割后的字符串对应的 token ID,如果找不到则使用未知 token ID。main 函数展示了如何调用 tokenize 函数并输出结果。llama.cpp 项目中的分词逻辑会更复杂,包括处理 BPE(字节对编码)、从模型文件中加载准确的词表等操作。完整详细的代码你可以从 llama.cpp 的官方 GitHub 仓库 中获取并进一步研究。llama.cpp 中,旋转位置编码(RoPE)相关的计算主要在 rope_f32 函数中实现。不过,llama.cpp 中的代码是用 C/C++ 编写的,与常见的 Python 实现有所不同。以下是对 llama.cpp 中 RoPE 实现过程的分析:precompute_freqs_cis 会先生成维度序列和频率基数,然后计算位置序列与频率的外积,最后转换为复数形式。在 llama.cpp 中,对应的逻辑可能会在相关的数据结构初始化或特定的函数中完成,例如在 llama_model_load 函数中,会根据模型的参数计算并存储 RoPE 的频率信息。apply_rotary_emb 函数首先重塑查询张量和键张量,然后提取频率的实部和虚部,接着应用旋转变换,最后重新组合实部和虚部。在 llama.cpp 中,rope_f32 函数会执行类似的操作。它会接收输入的张量数据,然后根据预计算的频率信息,对张量的每个元素进行旋转变换。具体来说,它会将张量的实部和虚部分别与频率的余弦和正弦值进行乘法运算,并进行相应的加法操作,以实现旋转。llama.cpp 的源代码中找到 rope_f32 函数。该函数通常位于 ggml-cuda.cu(如果是 CUDA 版本)或其他相关的源文件中。llama.cpp 项目中,rope_f32 函数(CPU 版本)用于实现旋转位置编码(RoPE)。以下是简化后的相关代码示例(实际代码可能因项目更新而略有不同,完整代码可从 llama.cpp 的 GitHub 仓库 获取 ),以便你理解其大致实现逻辑:#include <cmath>
#include <cstdint>
#include <vector>
// 辅助函数,计算正弦和余弦值
void sincos(float x, float *sin_val, float *cos_val) {
*sin_val = std::sin(x);
*cos_val = std::cos(x);
}
// RoPE函数实现
void rope_f32(
float *q, float *k,
const float *freqs,
int64_t n, int64_t dim, int64_t head_dim,
int64_t n_threads) {
for (int64_t i = 0; i < n; i++) {
for (int64_t j = 0; j < dim; j += head_dim) {
for (int64_t kk = 0; kk < head_dim; kk += 2) {
float q0 = q[i * dim + j + kk];
float q1 = q[i * dim + j + kk + 1];
float k0 = k[i * dim + j + kk];
float k1 = k[i * dim + j + kk + 1];
float f = freqs[kk / 2];
float cos_f, sin_f;
sincos(f, &sin_f, &cos_f);
// 应用RoPE旋转操作
float q0_prime = q0 * cos_f - q1 * sin_f;
float q1_prime = q0 * sin_f + q1 * cos_f;
float k0_prime = k0 * cos_f - k1 * sin_f;
float k1_prime = k0 * sin_f + k1 * cos_f;
q[i * dim + j + kk] = q0_prime;
q[i * dim + j + kk + 1] = q1_prime;
k[i * dim + j + kk] = k0_prime;
k[i * dim + j + kk + 1] = k1_prime;
}
}
}
}
sincos 函数用于计算给定角度的正弦和余弦值。rope_f32 函数是核心的 RoPE 实现部分:i。j。kk,提取查询向量 q 和键向量 k 的对应元素。f,计算出正弦和余弦值。q 和键向量 k 的对应元素应用旋转操作,更新它们的值。q 和键向量 k 应用旋转位置编码的过程。 llama.cpp 的 rope_f32 函数中同时对向量 q 和向量 k 进行计算,主要有以下原因:q 和键向量 k 都需要融入位置信息,且它们的旋转操作是基于相同的位置相关频率进行的。同时计算可以利用相同的频率信息,对 q 和 k 执行相似的旋转操作,以保证在注意力机制中,它们能正确地捕捉到位置信息,从而更好地处理文本中的长序列依赖关系。q 和 k 的计算放在一起,可以避免为 q 和 k 分别编写几乎相同的计算代码,减少了代码的重复,提高了代码的紧凑性和执行效率。在循环遍历位置、维度等操作时,同时对 q 和 k 进行处理,可以充分利用缓存和并行计算资源,减少计算时间和内存访问开销。llama 模型的注意力机制中,q 和 k 是相互作用的,它们共同决定了注意力的分布。同时计算 q 和 k 的旋转位置编码,有助于在模型的整体架构中,更自然地融合位置信息到注意力计算中,使得模型能够更好地理解文本的语义和结构。llama.cpp 的 rope_f32 函数中,kk 的步长设为2,每次计算两个点,主要有以下作用和好处:llama 模型中,向量的维度通常是偶数,并且在处理旋转位置编码时,是按照一定的维度分组进行的。步长为2与模型的维度结构相匹配,使得在对向量进行旋转操作时,能够准确地按照模型所需的方式更新每个维度的元素,保证位置编码的正确应用。Q和K与旋转以及实部虚部是有关系的。Q和K在经过旋转操作后,其方向和长度会根据位置信息发生变化,从而将位置信息融入到向量表示中。Q和K,但实际上是将它们的每个元素按照实部和虚部的概念来处理的。这是因为在数学上,旋转操作可以用复数乘法来表示。frequency(频率)通常是预先计算好的与位置相关的值,它确实也有实部和虚部(在代码中通过计算正弦和余弦值来体现)。在对Q和K进行旋转操作时,对于Q和K向量中的每两个相邻元素,分别将其视为类似复数的实部和虚部,然后根据frequency对应的正弦和余弦值进行旋转计算,就像在复数空间中进行旋转一样,从而实现将位置信息融入到Q和K向量中。llama.cpp 风格下,展示 rope_f32 函数调用以及相关参数来源的示例代码(为了便于理解做了一定简化和注释,实际完整的 llama.cpp 代码逻辑会更复杂,涉及很多模型相关的初始化等操作):#include <iostream>
#include <vector>
#include <cstdint>
#include <cmath>
// 定义rope_f32函数
void rope_f32(
float *q, float *k,
const float *freqs,
int64_t n, int64_t dim, int64_t head_dim,
int64_t n_threads) {
// 函数实现部分前面已展示,这里省略
for (int64_t i = 0; i < n; i++) {
for (int64_t j = 0; j < dim; j += head_dim) {
for (int64_t kk = 0; kk < head_dim; kk += 2) {
float q0 = q[i * dim + j + kk];
float q1 = q[i * dim + j + kk + 1];
float k0 = k[i * dim + j + kk];
float k1 = k[i * dim + j + kk + 1];
float f = freqs[kk / 2];
float cos_f, sin_f;
cos_f = std::cos(f);
sin_f = std::sin(f);
float q0_prime = q0 * cos_f - q1 * sin_f;
float q1_prime = q0 * sin_f + q1 * cos_f;
float k0_prime = k0 * cos_f - k1 * sin_f;
float k1_prime = k0 * sin_f + k1 * cos_f;
q[i * dim + j + kk] = q0_prime;
q[i * dim + j + kk + 1] = q1_prime;
k[i * dim + j + kk] = k0_prime;
k[i * dim + j + kk + 1] = k1_prime;
}
}
}
}
// 生成频率数组的辅助函数
std::vector<float> generate_freqs(int64_t dim) {
std::vector<float> freqs;
const float inv_freq = 1.0f / (10000.0f);
for (int64_t i = 0; i < dim / 2; i++) {
float f = std::pow(inv_freq, 2 * i / static_cast<float>(dim));
freqs.push_back(f);
}
return freqs;
}
int main() {
// 假设序列长度n为4
int64_t n = 4;
// 假设总维度dim为8
int64_t dim = 8;
// 假设每个头的维度head_dim为2
int64_t head_dim = 2;
// 假设线程数为1(这里简化,实际可能根据情况调整)
int64_t n_threads = 1;
// 生成查询向量q,这里简单初始化为全1,实际是通过模型的线性变换等得到
std::vector<float> q_vec(n * dim, 1.0f);
float *q = q_vec.data();
// 生成键向量k,这里简单初始化为全2,实际是通过模型的线性变换等得到
std::vector<float> k_vec(n * dim, 2.0f);
float *k = k_vec.data();
// 生成频率数组
std::vector<float> freqs = generate_freqs(dim);
const float *freqs_ptr = freqs.data();
// 调用rope_f32函数
rope_f32(q, k, freqs_ptr, n, dim, head_dim, n_threads);
// 输出处理后的q和k向量
std::cout << "处理后的查询向量q: ";
for (int64_t i = 0; i < n * dim; i++) {
std::cout << q[i] << " ";
}
std::cout << std::endl;
std::cout << "处理后的键向量k: ";
for (int64_t i = 0; i < n * dim; i++) {
std::cout << k[i] << " ";
}
std::cout << std::endl;
return 0;
}
generate_freqs 函数用于生成频率数组 freqs,它是根据 RoPE 中常见的频率生成公式来计算的。main 函数中:n 表示输入序列的长度,这里简单设为 4。dim 是向量的总维度,设为 8。head_dim 是每个头的维度,设为 2。n_threads 为线程数,这里设为 1。q_vec 和 k_vec 分别模拟查询向量 q 和键向量 k,实际在 llama.cpp 中它们是通过模型的线性变换等操作得到的。rope_f32 函数,传入相关参数,对 q 和 k 应用旋转位置编码,然后输出处理后的结果。llama.cpp 中旋转位置编码(RoPE)相关原理的理解和常见实现方式编写的示例,目的是为了展示相关逻辑,并非完全等同于实际 llama.cpp 项目中完整且精确的代码。llama.cpp 中,对于输入数据(包括 Q、K 向量等)的处理确实有其特定的流程,并不会随意“变掉原来模型的数据”。llama.cpp 中关于 RoPE 的实现代码,建议直接从 llama.cpp 的官方 GitHub 仓库 中获取并深入研究,那里的代码经过了实际的测试和优化,更能反映真实的情况。 import itertools
# 假设词汇表
vocabulary = ["你好", "世界", "Python", "自然语言处理"]
# 先将词汇表中的词汇编码为UTF-8字节串
encoded_vocabulary = [word.encode('utf-8') for word in vocabulary]
# 计算两个字节串的汉明距离
def hamming_distance(byte_str1, byte_str2):
xor_result = int.from_bytes(byte_str1, 'big') ^ int.from_bytes(byte_str2, 'big')
return bin(xor_result).count('1')
# 生成所有词汇对并计算汉明距离
pairs = list(itertools.combinations(encoded_vocabulary, 2))
distance_list = []
for pair in pairs:
dist = hamming_distance(pair[0], pair[1])
distance_list.append((pair[0].decode('utf-8'), pair[1].decode('utf-8'), dist))
# 按汉明距离排序
sorted_distances = sorted(distance_list, key=lambda x: x[2])
# 打印结果
for item in sorted_distances:
print(f"词汇对: {item[0]} 和 {item[1]}, 汉明距离: {item[2]}")
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
// 计算两个字节数组的汉明距离
int hamming_distance(const vector<unsigned char>& byte_arr1, const vector<unsigned char>& byte_arr2) {
int distance = 0;
for (size_t i = 0; i < min(byte_arr1.size(), byte_arr2.size()); ++i) {
unsigned char xor_result = byte_arr1[i] ^ byte_arr2[i];
while (xor_result) {
distance += xor_result & 1;
xor_result >>= 1;
}
}
return distance;
}
// 词汇对和汉明距离的结构体
struct PairDistance {
string word1;
string word2;
int distance;
};
int main() {
vector<string> vocabulary = {"你好", "世界", "Python", "自然语言处理"};
vector<vector<unsigned char>> encoded_vocabulary;
for (const string& word : vocabulary) {
vector<unsigned char> encoded_word(word.begin(), word.end());
encoded_vocabulary.push_back(encoded_word);
}
vector<PairDistance> distance_list;
for (size_t i = 0; i < vocabulary.size(); ++i) {
for (size_t j = i + 1; j < vocabulary.size(); ++j) {
int dist = hamming_distance(encoded_vocabulary[i], encoded_vocabulary[j]);
distance_list.push_back({vocabulary[i], vocabulary[j], dist});
}
}
// 按汉明距离排序
sort(distance_list.begin(), distance_list.end(), [](const PairDistance& a, const PairDistance& b) {
return a.distance < b.distance;
});
// 打印结果
for (const PairDistance& item : distance_list) {
cout << "词汇对: " << item.word1 << " 和 " << item.word2 << ", 汉明距离: " << item.distance << endl;
}
return 0;
}
hamming_distance 函数用于计算两个字节数组之间的汉明距离。PairDistance 结构体用于存储词汇对及其对应的汉明距离。main 函数中,先将词汇表中的词汇编码为字节数组,然后生成所有词汇对的汉明距离,并存储在 distance_list 中。sort 函数按汉明距离对 distance_list 进行排序,并输出结果。#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
// 计算两个字节数组的汉明距离
int hamming_distance(const vector<unsigned char>& byte_arr1, const vector<unsigned char>& byte_arr2) {
int distance = 0;
for (size_t i = 0; i < min(byte_arr1.size(), byte_arr2.size()); ++i) {
unsigned char xor_result = byte_arr1[i] ^ byte_arr2[i];
while (xor_result) {
distance += xor_result & 1;
xor_result >>= 1;
}
}
return distance;
}
// 词汇和汉明距离的结构体
struct WordDistance {
string word;
int distance;
};
int main() {
vector<string> vocabulary = {"你好", "世界", "Python", "自然语言处理"};
// 假设最简基础编码为 ASCII 字符 'a' 的 UTF-8 编码
vector<unsigned char> base_encoding = {'a'};
vector<WordDistance> distance_list;
for (const string& word : vocabulary) {
vector<unsigned char> encoded_word(word.begin(), word.end());
int dist = hamming_distance(encoded_word, base_encoding);
distance_list.push_back({word, dist});
}
// 按汉明距离排序
sort(distance_list.begin(), distance_list.end(), [](const WordDistance& a, const WordDistance& b) {
return a.distance < b.distance;
});
// 打印结果
for (const WordDistance& item : distance_list) {
cout << "词汇: " << item.word << ", 汉明距离: " << item.distance << endl;
}
return 0;
}
hamming_distance 函数依然用于计算两个字节数组之间的汉明距离。WordDistance 结构体用于存储词汇及其与基础编码的汉明距离。main 函数中,先定义了一个最简基础编码(这里是字符 'a' 的 UTF-8 编码),然后遍历词汇表,计算每个词汇的 UTF-8 编码与基础编码的汉明距离,并存储在 distance_list 中。sort 函数按汉明距离对 distance_list 进行排序,并输出结果。#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
// 计算两个字节数组按比特位置的距离
int bit_position_distance(const vector<unsigned char>& byte_arr1, const vector<unsigned char>& byte_arr2) {
int distance = 0;
size_t min_size = min(byte_arr1.size(), byte_arr2.size());
size_t max_size = max(byte_arr1.size(), byte_arr2.size());
// 遍历较短的字节数组
for (size_t i = 0; i < min_size; ++i) {
unsigned char byte1 = byte_arr1[i];
unsigned char byte2 = byte_arr2[i];
for (int j = 0; j < 8; ++j) {
// 如果当前比特位不同,计算位置距离
if ((byte1 & (1 << j)) != (byte2 & (1 << j))) {
// 找到byte1中当前比特位为1的位置
int pos1 = -1;
for (int k = j; k < 8; ++k) {
if (byte1 & (1 << k)) {
pos1 = k;
break;
}
}
// 找到byte2中当前比特位为1的位置
int pos2 = -1;
for (int k = j; k < 8; ++k) {
if (byte2 & (1 << k)) {
pos2 = k;
break;
}
}
// 如果两个位置都找到,计算距离并累加到总距离
if (pos1 != -1 && pos2 != -1) {
distance += abs(pos1 - pos2);
} else {
// 如果只有一个位置找到,将距离设为最大可能距离(这里设为8)
distance += 8;
}
}
}
}
// 处理较长字节数组中剩余的字节
for (size_t i = min_size; i < max_size; ++i) {
unsigned char byte = (min_size == byte_arr1.size()) ? byte_arr2[i] : byte_arr1[i];
for (int j = 0; j < 8; ++j) {
if (byte & (1 << j)) {
distance += 8; // 将剩余字节中为1的比特位距离设为最大可能距离
}
}
}
return distance;
}
// 词汇和比特位置距离的结构体
struct WordDistance {
string word;
int distance;
};
int main() {
vector<string> vocabulary = {"你好", "世界", "Python", "自然语言处理"};
// 假设最简基础编码为ASCII字符 'a'的UTF - 8编码
vector<unsigned char> base_encoding = {'a'};
vector<WordDistance> distance_list;
for (const string& word : vocabulary) {
vector<unsigned char> encoded_word(word.begin(), word.end());
int dist = bit_position_distance(encoded_word, base_encoding);
distance_list.push_back({word, dist});
}
// 按比特位置距离排序
sort(distance_list.begin(), distance_list.end(), [](const WordDistance& a, const WordDistance& b) {
return a.distance < b.distance;
});
// 打印结果
for (const WordDistance& item : distance_list) {
cout << "词汇: " << item.word << ", 比特位置距离: " << item.distance << endl;
}
return 0;
}
bit_position_distance 函数用于计算两个字节数组按比特位置的距离。函数首先遍历较短的字节数组,对于每个不同的比特位,找到两个字节中该比特位为 1 的位置,并计算它们的距离。如果只有一个字节中该比特位为 1,则将距离设为最大可能距离(这里设为 8)。然后处理较长字节数组中剩余的字节,将其中为 1 的比特位距离设为最大可能距离。最后,代码将词汇表中的每个词汇与基础编码进行比较,计算其比特位置距离,并按距离进行排序和输出。def binary_to_gray(n):
return n ^ (n >> 1)
# 示例用法
binary_num = 10 # 十进制的10,二进制为1010
gray_code = binary_to_gray(binary_num)
print(bin(gray_code))
binary_to_gray,它使用异或运算和右移运算将输入的自然二进制码转换为格雷码。public class BinaryToGray {
public static int binaryToGray(int n) {
return n ^ (n >> 1);
}
public static void main(String[] args) {
int binaryNum = 10;
int grayCode = binaryToGray(binaryNum);
System.out.println(Integer.toBinaryString(grayCode));
}
}
#include <iostream>
#include <bitset>
int binaryToGray(int n) {
return n ^ (n >> 1);
}
int main() {
int binaryNum = 10;
int grayCode = binaryToGray(binaryNum);
std::cout << std::bitset<8>(grayCode) << std::endl;
return 0;
}
gray2bin和bin2gray函数来进行格雷码和二进制码之间的转换,不过需要注意的是,Matlab 中的这些函数输入和输出通常是向量形式。^)和右移(>>)操作符来完成转换,以下是示例代码:#include <iostream>
#include <bitset>
// 将自然二进制码转换为格雷码的函数
int binaryToGray(int n) {
return n ^ (n >> 1);
}
int main() {
int binaryNum = 10; // 十进制的10,二进制为1010
int grayCode = binaryToGray(binaryNum);
std::cout << "二进制数 " << binaryNum << "(二进制表示:"
<< std::bitset<8>(binaryNum) << ")转换为格雷码后是:"
<< grayCode << "(二进制表示:" << std::bitset<8>(grayCode) << ")" << std::endl;
return 0;
}
binaryToGray 函数接受一个整数 n(表示自然二进制码),通过将 n 和 n 右移一位后的结果进行按位异或操作,返回对应的格雷码。在 main 函数中,定义了一个示例的二进制数 binaryNum,调用 binaryToGray 函数进行转换,并使用 std::bitset 来展示二进制数和格雷码的二进制表示形式。0x00 0x00 0x61 0x62,先将其看作二进制数00000000 00000000 01100001 01100010,再通过n ^ (n >> 1)的方式转换为格雷码。1101和1111,通过按位异或得到0010,其中1的个数为 1,即汉明距离为 1。