【问题标题】:Translate this C function to PHP将此 C 函数转换为 PHP
【发布时间】:2013-09-25 22:58:10
【问题描述】:

我正在尝试将以下 C 代码(基本上只是尝试将任意整数值转换为字符池中的字符)转换为 PHP:

#include <cstdint>
#include <cstring>
#include <iostream>

uint8_t GetCharacter(uint32_t value) {
    static const char* valid_characters = "0123456789ABCDEFGHIJKLMOPQRSTUVWabcdefghijklmnopqrstuvw";
    static const size_t valid_characters_l = strlen(valid_characters);
    uint8_t c = valid_characters[value % valid_characters_l];
    return valid_characters[(value << c) % valid_characters_l];
}

int main() {
    uint32_t array[] = {176, 52, 608, 855};
    for (size_t i=0; i < 4; i++) {
        uint8_t c = GetCharacter(array[i]);
        std::cout << array[i] << ": " << (uint32_t) c << "\n";
    }
    return 0;
}

产量

176: 109
52: 114
608: 85
855: 65

我已经能够提出的 PHP 代码产生以下结果:

176: 109
52: 114
608: 85
855: 104   // << Here's the problem

我很确定我准确地翻译了它,但我找不到问题。

<?php

function getCharacter($index) {
    $chars = "0123456789ABCDEFGHIJKLMOPQRSTUVWabcdefghijklmnopqrstuvw";
    $c = ord(substr($chars, $index % strlen($chars)));
    return ord(substr($chars, ($index << $c) % strlen($chars)));
}

function main() {
    $array = array(176, 52, 608, 855);
    foreach ($array as $value) {
        echo "$value: " . getCharacter($value) . "\n";
    }
}

main();

有人能指出我解决这个问题的正确方向吗?

【问题讨论】:

  • 在我的机器上工作 - 你使用的是什么版本的 PHP?
  • 我会打印出strlen($chars)$index$c 的值,作为调试的第一步。由于机器上的位数,您可能遇到移位操作溢出的问题。原则上$c可以>32...

标签: php c++ code-translation


【解决方案1】:

我认为问题在于数字 ($index &lt;&lt; c)3,586,129,920 > 20 亿,并且不能用带符号的 32 位整数正确表示。由于您没有在 php 中明确定义 $value 的数据类型,我认为算术最终取决于实现。

实际上,令人惊讶的是,事情完全正常——我认为,你正在将一个 32 位数字移动一个大于 32 的值,这将导致未定义的行为。您可能需要重新考虑底层数学,特别是考虑代码的下溢/溢出行为。

作为一种潜在的解决方案,您可能会注意到您有有限数量的可能输入和相应的输出 - 您实际上可以创建一个直接查找表。我相信我正确地做到了这一点(使用您的代码的 C++ 版本并进行了一些修改)——它没有导致 1:1 映射让我有点惊讶。查找字符串变为:

$lookupString = "6RQtrpp07TU4AP1IDKmjl8QD7WjitmwUAcjT3AT9MuAu3PUKJtIb5vS"

而且你的php代码可以简化为

$value = ord(substr($lookupString, $input % 55));

其中55lookupString 的长度。

有趣的观察:多个字符多次出现;从不使用其他字符。这意味着这不是一个非常“好”的编码方案(如果这是它想要的)。

作为参考,这是我用来确定查找字符串的代码:

#include <cstring>
#include <iostream>

static const char* valid_characters = "0123456789ABCDEFGHIJKLMOPQRSTUVWabcdefghijklmnopqrstuvw";

uint8_t GetCharacter(uint32_t value) {
    static const size_t valid_characters_l = strlen(valid_characters);
    uint8_t c = valid_characters[value % valid_characters_l];    
    return valid_characters[(value << c) % valid_characters_l];
}

int main() {
    uint32_t array[] = {176, 52, 608, 855};
    for (size_t i=0; i < 55; i++) {
        uint8_t c = GetCharacter(i + '0');
        std::cout << char(c);
    }
    std::cout << "\n";
    return 0;
}

【讨论】:

    【解决方案2】:

    您几乎肯定会遇到“问题”,因为您运行的是 32 位 PHP 或 Windows 上的 PHP(无论操作系统位数如何,它都不支持 64 位整数)。问题是您在移位操作中溢出了整数:

    64 位 PHP:

    PHP_INT_MAX: 9223372036854775807
    C: 66, index: 176, strlen: 55, shift: 704, substr: mnopqrstuvw :: 176: 109
    C: 117, index: 52, strlen: 55, shift: 468374361246531584, substr: 9ABCDEFGHIJKLMOPQRSTUVWabcdefghijklmnopqrstuvw :: 52: 57
    C: 51, index: 608, strlen: 55, shift: 1369094286720630784, substr: hijklmnopqrstuvw :: 608: 104
    C: 86, index: 855, strlen: 55, shift: 3586129920, substr: ABCDEFGHIJKLMOPQRSTUVWabcdefghijklmnopqrstuvw :: 855: 65
    

    32 位 PHP:

    PHP_INT_MAX: 2147483647
    C: 66, index: 176, strlen: 55, shift: 704, substr: mnopqrstuvw :: 176: 109
    C: 117, index: 52, strlen: 55, shift: 109051904, substr: rstuvw :: 52: 114
    C: 51, index: 608, strlen: 55, shift: 318767104, substr: UVWabcdefghijklmnopqrstuvw :: 608: 85
    C: 86, index: 855, strlen: 55, shift: -708837376, substr: hijklmnopqrstuvw :: 855: 104
    

    不幸的是,PHP 在 32 位系统上根本不支持长整数(目前)。解决这个问题的唯一方法是通过像GMPBCMath 这样的外部包。今年晚些时候发布PHP v7.0时,这个问题should be fixed

    【讨论】:

    • 我不认为 BCMath 支持按位运算,但我可能错了。
    • @Amal:没错,但它确实支持乘法、除法和幂。左右移位基本上只是乘以 2 的幂。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 2015-01-17
    • 2011-11-01
    • 1970-01-01
    • 2015-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多