lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Thu, May 7, 2015 at 10:13 PM, "书呆彭, Peng Yi" <nerditation@outlook.com> wrote:
> 在 2015/5/8 1:20, Paulo Roberto 写道:
>>
>> I just tried to use *string.format* instead of using the operator *..* and
>> it worked fine.
>> The new Lua code:
>>
>> /if (lua_type == 'transaction') then
>>   shiftno = tran.getshiftno()
>>   dev.log(string.format('ShiftNumber: %d' , shiftno))
>>   tran.print(string.format('ShiftNumber: %d' , shiftno))
>> end/
>>
>> The question is: why the operator *..* does not work on this platform and
>> works on Linux and others platforms I have here.
>> The Lua source code used to build the libraries were the same.
>>
>> Thank you again.
>>
>> Regards.
>>
>> On Thu, May 7, 2015 at 11:50 AM, Paulo Roberto <betobrandao@gmail.com
>> <mailto:betobrandao@gmail.com>> wrote:
>>
>>     Hello,
>>
>>     I'm getting a strange behavior using the functions /lua_pushinteger/
>> and /lua_pushunsigned/.
>>
>>     When calling these functions, the value stored in the Lua stack /L/ is
>> not the value passed to the function (an integer), actually It is a small
>> float number.
>>     It seems there is some sort of error converting values as all Lua
>> numbers are stored as /double/ numbers.
>>
>>     For example, passing the value /37/, the Lua layer receives
>> /5.3265215697135e-315/
>>
>>     I'm using *lua 5.2*, *gcc 4.3.4*, building for ARM processors, 32 bits
>> words.
>>     I'm passing the compile flag/LUA_COMPAT_ALL/ and /LUA_ANSI/
>>
>>
>>     The code I'm using is something like this:
>>
>>
>>     /int GetShiftNumber(lua_State *L)
>>     {
>>       lua_pushinteger(L, gsConfig.ShiftNumber);
>>     #ifdef RUNLOG2
>>       sprintf(NurLogBuf, "GetShiftNumber: shiftno = %lu",
>> gsConfig.ShiftNumber);
>>       Log2(NurLogBuf);
>>     #endif
>>       return(1);
>>     }
>>
>>     /
>>     The/Log2/ just logs the values on the RS232 port.
>>
>>     The Lua code that invokes the C code above is:
>>
>>     /if (lua_type == 'transaction') then
>>       shiftno = tran.getshiftno()
>>       dev.log('ShiftNumber: ' .. shiftno)
>>       tran.print('ShiftNumber: ' .. shiftno)
>>     end
>>
>>     /
>>     /
>>     /
>>     The/tran.getshiftno/ is the corresponding Lua function for the above
>> /GetShiftNumber/.
>>     The /dev.log/ function just invokes the C Log2 function.
>>
>>
>>     On the C layer, the variables are correct displayed:
>>
>>     /GetShiftNumber: shiftno = 37/
>>
>>     On the Lua layer, the /shiftno/ is incorrect, /dev.log/ displays:
>>
>>     /ShiftNumber 5.3265215697135e-315/
>>
>>     The /gsConfig/ is a global structure and the
>> field/gsConfig.ShiftNumber/ is an /unsigned long/.
>>     I also tried to use the lua_pushunsigned and got the same result.
>>     Then I created a local /int/ variable, did and explicit cast and
>> passed the local variable to /lua_pushinteger/ but nothing changed.
>>
>>     Passing values from Lua layer to C layer works fine.
>>     The same code, works fine in other platforms.
>>
>>     Could you help me to find a solution for this issue?
>>
>>     Thank you in advance.
>>
>>     Paulo Roberto Brandão.
>>
>>
> I guess it's a flaw of the CRT on your device, or you just misconfigured
> Lua.
>
> I remember `tostring` use the `%g` format to convert a number to string
> under
> the default configuration. either you libc doesn't deal with `%g` correctly,
> or
> you have a configuration using other format specifier.
>
> check your `luaconf.h`; I believe the config definition is called
> `number2str`.
>
>
> --
> the nerdy Peng / 书呆彭 / Sent from Thunderbird
>
>
>

A quick test shows that 37 = 0x25, and 5.3265215697135e-315 is close
to a double value that begins with 0x25 (probably it's been rounded),
so I suspect some code is assuming it's been given a pointer to a
double when in fact it has a pointer to a uint8_t*.

The (quick, hacky, ugly) test I used was:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

static void dump(uint8_t *var, int count) {
    while(count > 0) {
        printf("%02X ", *var);
        var++;
        count--;
    }
    printf("\n");
}

int main(int argc, char **argv) {
    double d = 5.3265215697135e-315;
    float  f = (float)d;

    printf("d = %1.16g: ", d);
    dump((uint8_t*)&d, sizeof(d));

    printf("f = %1.16g: ", f);
    dump((uint8_t*)&f, sizeof(f));

    (*(uint8_t*)&d) = 37;
    printf("d = %1.16g: ", d);
    dump((uint8_t*)&d, sizeof(d));

    f = (float)d;
    printf("f = %1.16g: ", f);
    dump((uint8_t*)&f, sizeof(f));

    (*(uint8_t*)&f) = 37;
    printf("f = %1.16g: ", f);
    dump((uint8_t*)&f, sizeof(f));

    return 0;
}

The output on my system is:
~> gcc test.c -o test && ./test
d = 5.326521569713472e-315: 00 80 42 40 00 00 00 00
f = 0: 00 00 00 00
d = 5.326521752517761e-315: 25 80 42 40 00 00 00 00
f = 0: 00 00 00 00
f = 5.184804318001823e-44: 25 00 00 00

(The actual constant given in OP's message doesn't begin with 0x25,
but it's likely been rounded somewhat; the test demonstrates that
changing the first byte to 0x25 changes the value only slightly.)

-- 
Sent from my Game Boy.