Half-Life и Adrenaline Gamer форум

Всё об игре в Халф-Лайф и АГ
Текущее время: 18 апр 2024, 18:38

Часовой пояс: UTC + 5 часов [ Летнее время ]




Начать новую тему Ответить на тему  [ Сообщений: 2 ] 
Автор Сообщение
СообщениеДобавлено: 28 янв 2016, 13:53 
Не в сети
Зарегистрирован:
06 авг 2010, 10:25
Последнее посещение:
20 янв 2021, 16:32
Сообщения: 695
Откуда: Uzbekistan
Столкнулся с так называемой проблемой точности дробных чисел.

Для примера:
Код:
new Float:leet = 13.37
server_print("--> %f %.2f")
Цитата:
--> 13.369999 13.36

Придумал вот что:
Код:
Float:floatfractround(Float:value)
{
   new Float:f =floatfract(value)
   new bool:is_rev = value < 0.0
   
   value = floatsub(floatabs(value),f)
   value = floatadd(value,(floatround(f * 100.0) / 100.0 + 0.00001))
   
   return !is_rev ? value : -value
}
Код:
new Float:leet = 13.37
server_print("--> %f %.2f | %f %.2f",leet,leet,floatfractround(leet),floatfractround(leet))
Цитата:
--> 13.369999 13.36 | 13.370010 13.37

И так сойдет или есть вариант лучше?


Вернуться к началу
 Профиль 
  
СообщениеДобавлено: 28 янв 2016, 15:57 
Не в сети
Site Admin
Зарегистрирован:
01 июн 2010, 01:27
Последнее посещение:
18 апр 2024, 17:14
Сообщения: 6867
В AMXX используется собственная имплементация printf.
Тут написано что в обычном printf используется округление к ближайшему четному.
Проверяем:
Код:
#include <amxmodx>

public plugin_init()
{
   register_plugin("test", "0.0", "Lev");
   register_srvcmd("test", "cmd_test");
}

public cmd_test(id)
{
   new range = 21;
   new Float:f;

   server_print("------------");
   f = 13.37;
   server_print("--> %f %.2f", f, f);
   f = 13.36;
   server_print("--> %f %.2f", f, f);

   server_print("------------");
   f = 13.30;
   for (new i = 0; i < range; i++)
   {
      server_print("--> %f %.2f", f, f);
      f += 0.001;
   }
   server_print("------------");
   f = -13.30;
   for (new i = 0; i < range; i++)
   {
      server_print("--> %f %.2f", f, f);
      f -= 0.001;
   }
}
Цитата:
------------
--> 13.369999 13.36
--> 13.359999 13.35
------------
--> 13.300000 13.30
--> 13.301000 13.30
--> 13.302000 13.30
--> 13.303001 13.30
--> 13.304001 13.30
--> 13.305002 13.30
--> 13.306002 13.30
--> 13.307003 13.30
--> 13.308003 13.30
--> 13.309003 13.30
--> 13.310004 13.31
--> 13.311004 13.31
--> 13.312005 13.31
--> 13.313005 13.31
--> 13.314005 13.31
--> 13.315006 13.31
--> 13.316006 13.31
--> 13.317007 13.31
--> 13.318007 13.31
--> 13.319007 13.31
--> 13.320008 13.32
------------
--> -13.300000 -13.30
--> -13.301000 -13.30
--> -13.302000 -13.30
--> -13.303001 -13.30
--> -13.304001 -13.30
--> -13.305002 -13.30
--> -13.306002 -13.30
--> -13.307003 -13.30
--> -13.308003 -13.30
--> -13.309003 -13.30
--> -13.310004 -13.31
--> -13.311004 -13.31
--> -13.312005 -13.31
--> -13.313005 -13.31
--> -13.314005 -13.31
--> -13.315006 -13.31
--> -13.316006 -13.31
--> -13.317007 -13.31
--> -13.318007 -13.31
--> -13.319007 -13.31
--> -13.320008 -13.32
Со всей очевидностью, применяется округление отбрасыванием (windows/linux, amxx 1.8.1).
Поэтому используем самое простое решение:
Код:
#include <amxmodx>

public plugin_init()
{
   register_plugin("test", "0.0", "Lev");
   register_srvcmd("test", "cmd_test");
}

public cmd_test(id)
{
   new range = 21;
   new Float:f;

   server_print("------------");
   f = 13.37;
   server_print("--> %f %.2f", f, f >= 0 ? f + 0.005 : f - 0.005);
   f = 13.36;
   server_print("--> %f %.2f", f, f >= 0 ? f + 0.005 : f - 0.005);

   server_print("------------");
   f = 13.30;
   for (new i = 0; i < range; i++)
   {
      server_print("--> %f %.2f", f, f >= 0 ? f + 0.005 : f - 0.005);
      f += 0.001;
   }
   server_print("------------");
   f = -13.30;
   for (new i = 0; i < range; i++)
   {
      server_print("--> %f %.2f", f, f >= 0 ? f + 0.005 : f - 0.005);
      f -= 0.001;
   }
}
Цитата:
------------
--> 13.369999 13.37
--> 13.359999 13.36
------------
--> 13.300000 13.30
--> 13.301000 13.30
--> 13.302000 13.30
--> 13.303001 13.30
--> 13.304001 13.30
--> 13.305002 13.31
--> 13.306002 13.31
--> 13.307003 13.31
--> 13.308003 13.31
--> 13.309003 13.31
--> 13.310004 13.31
--> 13.311004 13.31
--> 13.312005 13.31
--> 13.313005 13.31
--> 13.314005 13.31
--> 13.315006 13.32
--> 13.316006 13.32
--> 13.317007 13.32
--> 13.318007 13.32
--> 13.319007 13.32
--> 13.320008 13.32
------------
--> -13.300000 -13.30
--> -13.301000 -13.30
--> -13.302000 -13.30
--> -13.303001 -13.30
--> -13.304001 -13.30
--> -13.305002 -13.31
--> -13.306002 -13.31
--> -13.307003 -13.31
--> -13.308003 -13.31
--> -13.309003 -13.31
--> -13.310004 -13.31
--> -13.311004 -13.31
--> -13.312005 -13.31
--> -13.313005 -13.31
--> -13.314005 -13.31
--> -13.315006 -13.32
--> -13.316006 -13.32
--> -13.317007 -13.32
--> -13.318007 -13.32
--> -13.319007 -13.32
--> -13.320008 -13.32

Можно пойти чуточку дальше и сэкономить на нативах:
Код:
   server_print("--> %f %.2f", f, _:f >= 0 ? f + 0.005 : f - 0.005);
Было:
Код:
 0x1EC       LOAD.S.pri             -0x4
 0x1F4       MOVE.alt 
 0x1F8       ZERO.pri 
 0x1FC       PUSH.pri 
 0x200       PUSH.pri 
 0x204       PUSH.alt 
 0x208       PUSH.C                  0x8
 0x210       CALL          operator>=(Float:,_:)
 0x218       POP.alt   
 0x21C       JZER              jump_0000
Стало:
Код:
 0x2E4       LOAD.S.pri             -0x4
 0x2EC       MOVE.alt 
 0x2F0       ZERO.pri 
 0x2F4       XCHG     
 0x2F8       JSLESS            jump_0002

Добавлено спустя 2 часа 51 минуту 17 секунд:
UPD: поправил насчет printf.


Вернуться к началу
 Профиль 
  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 2 ] 

Часовой пояс: UTC + 5 часов [ Летнее время ]


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB