C002-CPP-Luhn公式

本文详细介绍了Luhn算法的工作原理及其验证流程,并提供了一段用于验证数字串合法性的C++实现代码。Luhn算法常用于银行卡号等的合法性验证。

使用Luhn算法检验 键入的一串数字 是否合法


Luhn算法:

Luhn 是 模10算法:

符合Luhn算法的数字串包含2部分:具体数字(任意长度) + 校验数字(1个)
比如[1762483],符合Luhn算法,它的两部分是:[176248] + [3]
具体数字是任意的数字,它的校验数字是通过Luhn算法算出来的,计算后得到的整个数字串符合Luhn算法

Luhn算法的步骤:

假设数字串[176248]的校验数字是X,即整个数字串是[176248X],求出X的步骤如下:
1、从[176248X]的右边开始数,偶数位置的数字是[7,2,8],奇数位置的数字是[1,6,4,X]
2、将奇数位的数字相加:sum = 1 + 6 + 4 + X = 11 + X
3、将偶数位的数字都乘以2,得到数字串:[14,4,16]
4、将这个数字串中大于等于10的数字的十位和个位拆开,分别成为2个独立的数字:[1,4,4,1,6]
5、再将这个数字串的每一位加到sum中去:sum = 11 + X + 1 + 4 + 4 + 1 + 6 = 27 + X
6、Luhn算法要求sum必须可以被10整除,而X必须是1位数,所以X = 3,sum = 27 + 3 = 30,sum % 10 = 30 % 10 = 0
7、于是数字串[176248]加上的校验数字是3:1762483


上面是假设数字串已经符合Luhn算法,然后求出校验数字,这用来生成符合Luhn算法的数字串


下面的代码用来检验一个数字串是否符合Luhn算法,即在校验数字已知的情况下,检验数字串的sum是否可以被10整除


代码:

2_3_Luhn.cpp

// ==========================================================================================================
// 2-3节,Luhn算法:检验键入的一串数字是否合法
// 
// ==========================================================================================================
#include "2_3_Luhn.h"

#include <iostream>
// ----------------------------------------------------------------------------------------------------------
//      包含namespace std (@ iostream):
// (1). 换行符用"endl"指令,意为end of line
// (2). cin >> val 是函数调用,成功输入数据到val,返回TRUE,否则返回FALSE
// ----------------------------------------------------------------------------------------------------------
using namespace std;

#define DEBUG   1

// ==========================================================================================================
// 返回一个Luhn数的和
// 
// ==========================================================================================================
int Luhn_get_sum(int data)
{
    int temp;
    int sum;

    if(data > 9)
    {
        cout << "A Luhn number can not bigger than 9" << endl;
        return -1;
    }
    temp = data * 2;
    if(temp >= 10) { sum = 1 + temp % 10; }
    else           { sum = temp; }

    return sum;
}

// ==========================================================================================================
// Luhn公式:求键入的一串数字的Luhn和
// 
// 参数:sum     数字串的Luhn和
//       length  数字串的长度
// 
// (1). 输入的数字字符必须是ASCII码的字符、或是从0到9依次排列的数字字符
// 
// ==========================================================================================================
void Luhn_sum(int *sum, int *length)
{
    char number;    // 接收输入的数字串中的一个元素
    int  count = 0; // 记录数字串的长度
    int  sum_odd  = 0;
    int  sum_even = 0;

    cout << "Enter your number : ";
    while(1)
    {
        cin.get(number);
        if(('\n' == number) || ('\r' == number)) { break; }
        number -= '0';   // 减去序列中的第1个字符(不写成10,因为'0'字符在不同编码系统中的具体值可能不一样)
        count++;
        if(0 == (count % 2))                    // 从左到右数的偶数序列
        {                                       // 
            sum_odd  += Luhn_get_sum(number);   // 奇数长度的数字串:需要翻倍
            sum_even += number;                 // 偶数长度的数字串:不需要翻倍
        }
        else                                    // 从左到右数的奇数序列
        {
            sum_odd  += number;                 // 奇数长度的数字串:不需要翻倍
            sum_even += Luhn_get_sum(number);   // 偶数长度的数字串:需要翻倍
        }
#if DEBUG
        cout << '[' << '(' << count << ") " << (int)number << ',' << sum_odd  << ',' << sum_even  << ']' << endl;
#endif
    }
    *length = count;
    if(0 == (count % 2))
    { *sum = sum_even; }    // 长度为偶数
    else               
    { *sum = sum_odd;  }    // 长度为奇数
}

// ==========================================================================================================
// Luhn公式:检验键入的一串数字是否合法
// 
// ==========================================================================================================
void Luhn_check(void)
{
    int sum;
    int length;

    Luhn_sum(&sum, &length);
#if DEBUG
    cout << "The length of the input numbers = " << length << endl;
    cout << "and the Luhn-sum = " << sum << endl;
#endif
    cout << "The input numbers is " 
         << ((0 == (sum % 10)) ? "LEGAL" : "ILLEGAL" )
         << " (According to Luhn-Rule)" 
         << endl;
}
main.c

// ==========================================================================================================
// 主函数
// ==========================================================================================================


#include <malloc.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

#include "2_3_Luhn.h"

// ==========================================================================================================
// main函数
// 
// ==========================================================================================================
int main(void)
{
// ----------------------------------------------------------------------------------------------------------
//  使用Luhn公式对输入数字串进行检验
    while(1)
    { Luhn_check(); }

// ----------------------------------------------------------------------------------------------------------
    system("pause");
    return 0;
}

测试结果:

(1). 使用Luhn公式作为输入检查的号码:银行卡卡号。

       因而可以使用银行卡卡号来检验。

       这里测试了多个银行卡卡号,结果都OK。

(2). ISBN和身份证等数字串不是使用上面的Luhn算法得出的。




C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: FATAL EXCEPTION: Thread-3 C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: Process: com.duokan.phone.remotecontroller, PID: 5648 C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: java.lang.UnsupportedOperationException: C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.os.Parcel.createExceptionOrNull(Parcel.java:3254) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.os.Parcel.createException(Parcel.java:3226) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:3209) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:3151) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.hardware.IConsumerIrService$Stub$Proxy.transmit(IConsumerIrService.java:182) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.hardware.ConsumerIrManager.transmit(ConsumerIrManager.java:84) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at je.g.o(Unknown Source:20) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at je.g.g(Unknown Source:2) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at je.g.b(Unknown Source:0) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at je.f.run(Unknown Source:8) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:959) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:100) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:232) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.os.Looper.loop(Looper.java:317) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at je.g.f(Unknown Source:10) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at je.g.a(Unknown Source:0) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at je.e.run(Unknown Source:2) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at java.lang.Thread.run(Thread.java:1012) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: Caused by: android.os.RemoteException: Remote stack trace: C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.os.Parcel.createExceptionOrNull(Parcel.java:3254) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.os.Parcel.createException(Parcel.java:3226) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:3209) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:3151) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: at android.hardware.ir.IConsumerIr$Stub$Proxy.transmit(IConsumerIr.java:164) C002DCA 08-14 13:35:30.466 5648 5679 E AndroidRuntime: 解释一下这个报错
08-19
<think>我们正在处理一个Android开发中的异常:`java.lang.UnsupportedOperationException`,发生在`IConsumerIrService.transmit`方法调用时。 这个异常通常表示设备不支持所调用的方法。具体到红外传输(Consumer Infrared),意味着设备没有红外发射器,或者系统没有提供相应的API实现。 分析步骤: 1. **检查设备是否支持红外功能**:在调用`transmit`方法之前,应该先检查设备是否有红外发射器。 2. **检查API可用性**:即使设备有红外硬件,也可能因为系统版本或厂商定制的原因,没有提供标准的红外API。 解决方案: 在调用红外传输方法之前,进行以下检查: a. **检查设备是否有红外发射器**: 可以通过`PackageManager`来检查设备是否支持红外功能。 ```java PackageManager packageManager = context.getPackageManager(); boolean hasIrEmitter = packageManager.hasSystemFeature(PackageManager.FEATURE_CONSUMER_IR); if (!hasIrEmitter) { // 设备不支持红外 return; } ``` b. **获取`ConsumerIrService`**: 通过系统服务获取`ConsumerIrService`。 ```java ConsumerIrManager irManager = (ConsumerIrManager) context.getSystemService(Context.CONSUMER_IR_SERVICE); ``` c. **检查`irManager`是否为null**: 如果设备不支持,`irManager`可能为null。 ```java if (irManager == null) { // 设备不支持红外 return; } ``` d. **检查`irManager`是否支持传输**: 在调用`transmit`之前,可以尝试检查是否有可用的红外载波频率。 ```java if (!irManager.hasIrEmitter()) { // 红外发射器不可用 return; } ``` 但是,即使做了以上检查,仍然可能遇到`UnsupportedOperationException`。这是因为有些设备厂商可能没有正确实现红外API,或者在某些设备上该方法被故意禁用。 另外,根据Android官方文档,`ConsumerIrManager`的`transmit`方法在API级别19(Android 4.4)中引入。因此,在调用之前,还需要确保系统版本至少是API 19。 如果以上检查都通过,但仍然出现异常,那么可能是设备特定的问题。建议在调用`transmit`方法时使用try-catch捕获异常。 示例代码: ```java try { irManager.transmit(frequency, pattern); } catch (UnsupportedOperationException e) { // 处理异常,例如提示用户设备不支持 e.printStackTrace(); } ``` 总结: 在调用任何可能不被设备支持的系统API时,都应该进行前置条件检查,并捕获可能抛出的异常。 引用说明: 在Android开发中,设备硬件支持情况因设备而异,因此必须进行运行时检查。Android官方文档中强调了通过`PackageManager`检查系统特性,以及在使用硬件相关API时进行空值检查[^1]。 相关问题: 1. 如何在Android中检查设备是否支持特定硬件功能? 2. 如何处理Android中硬件相关的API调用异常? 3. Android红外API的使用方法和兼容性处理有哪些注意事项?</think>### Android `java.lang.UnsupportedOperationException` in `IConsumerIrService.transmit` 分析 这个异常发生在调用 Android 红外传输 API 时,表示设备**不支持红外发射功能**或**当前 API 调用无效**。以下是详细分析和解决方案: #### 1. **异常原因** - **设备无红外硬件**:设备没有物理红外发射器(如某些低端机型)[^1] - **系统级限制**:制造商禁用了红外 API 或未实现相关服务 - **API 使用错误**: - 调用了未实现的 `transmit()` 方法 - 使用了无效的红外信号参数(频率/模式) - 未检查设备支持性直接调用 API - **权限问题**:缺少 `USE_IR` 权限声明(Android 4.4+ 需要) #### 2. **解决方案** ##### (1) 检查设备红外支持性 ```java // 检查硬件支持 ConsumerIrManager irManager = (ConsumerIrManager) getSystemService(Context.CONSUMER_IR_SERVICE); if (irManager == null || !irManager.hasIrEmitter()) { // 设备不支持红外 Toast.makeText(this, "设备无红外功能", Toast.LENGTH_SHORT).show(); return; } ``` ##### (2) 正确声明权限(AndroidManifest.xml) ```xml <uses-permission android:name="android.permission.TRANSMIT_IR" /> <uses-feature android:name="android.hardware.consumerir" /> ``` ##### (3) 安全调用 API(带异常捕获) ```java try { // 示例:发射38kHz红外信号(需替换真实参数) int carrierFrequency = 38000; int[] pattern = {1000, 500, 1000}; // 信号模式 irManager.transmit(carrierFrequency, pattern); } catch (UnsupportedOperationException e) { // 处理异常 Log.e("IR_ERROR", "红外传输不支持: " + e.getMessage()); } ``` ##### (4) 验证参数有效性 - **频率范围**:通常需在 $[20000, 60000] \text{Hz}$ 之间 - **模式数组**:长度需为**偶数**(交替的开/关时间) - 使用前检查可用频率: ```java ConsumerIrManager.CarrierFrequencyRange[] freqs = irManager.getCarrierFrequencies(); ``` #### 3. **备选方案** - **使用厂商 SDK**:部分品牌(如 Samsung/Xiaomi)提供私有红外 API - **硬件兼容模式**:添加备用控制逻辑(如 WiFi/蓝牙) ```java if (Build.MANUFACTURER.equalsIgnoreCase("samsung")) { // 调用三星私有API } else { // 使用标准API } ``` #### 4. **调试建议** - 在模拟器上测试时强制跳过红外调用 - 使用设备信息 API 过滤无红外硬件的设备: ```java PackageManager pm = getPackageManager(); boolean hasIR = pm.hasSystemFeature(PackageManager.FEATURE_CONSUMER_IR); ``` > **关键提示**:此异常本质是设备硬件限制,完整解决方案需包含硬件检测→参数校验→异常捕获→备用方案四层处理[^1]。 ### 相关问题 1. 如何在 Android 中检测设备是否支持特定硬件功能(如 NFC/红外)? 2. Android 硬件兼容性异常的最佳处理模式是什么? 3. 如何为不同厂商设备实现统一红外控制功能? 4. Android 系统服务调用时的常见异常类型有哪些? [^1]: 在 Android 开发中,硬件相关 API 调用前必须进行特性检测,否则会触发 `UnsupportedOperationException`。详见 [Android 红外文档](https://developer.android.com/reference/android/hardware/ConsumerIrManager)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值