In response to Bl4ck Adam
10/10
In response to MagicMountain
Now if only we can get some raycast lighting going on, then we'd have something super awesome.
In response to Rushnut
Rushnut wrote:
That looks fantastic, it's really wonderful to see the SS13 community integrating with this thread, we'd love to see more of you!

Have to agree. It's good to see you (MM) and a few others from SS13 interacting with the main site on a regular basis. It seems like it just used to be an occasional bitch session from one side or the other, but the mostly civil and intelligent discourse over the last year or two has been much more productive. I think you guys have helped push LummoxJR and the engine quite a bit.

Those screenshots look pretty damn good too. Congrats on the update.
In response to Nadrew
Nadrew wrote:
Now you guys just need to box that lighting stuff up into a library for the masses.

Please! +1
In response to Exentriks Gaming
Exentriks Gaming wrote:
Nadrew wrote:
Now you guys just need to box that lighting stuff up into a library for the masses.

Please! +1

+1
Since I won't be taking my finals, I figured I'd work on my BigInt library again. I think I have multiplication functioning now, though I want to try and work out some ways to speed it up as it's still a little slow. This is the profiler output from multiplying two 400 hexadecimal digit (approximately 480 decimal digit) numbers
/*
Profile results (total time)
Proc Name Self CPU Total CPU Real Time Calls
--------------------------------- --------- --------- --------- ---------
/mob/verb/MultiplyTest 0.000 0.233 0.233 1
/pif_BigInt/New 0.001 0.001 0.001 3
/pif_BigInt/proc/_GetBlock 0.026 0.033 0.038 22001
/pif_BigInt/proc/_SetBlock 0.034 0.039 0.039 20400
/pif_BigInt/proc/BitLength 0.000 0.000 0.000 3
/pif_BigInt/proc/BitsInteger 0.004 0.011 0.012 1600
/pif_BigInt/proc/LargestBit 0.000 0.000 0.000 2
/pif_BigInt/proc/Length 0.012 0.012 0.016 43206
/pif_BigInt/proc/Multiply 0.138 0.207 0.207 1
/pif_BigInt/proc/PrintHex 0.000 0.025 0.025 3
/pif_BigInt/proc/PrintHexadecimal 0.014 0.025 0.025 3
/pif_BigInt/proc/Set 0.000 0.001 0.001 3
/pif_BigInt/proc/SetLength 0.004 0.005 0.005 199
/pif_BigInt/proc/SetSign 0.000 0.000 0.000 1
/pif_BigInt/proc/Sign 0.000 0.000 0.000 3
*/

and the actual output
0x638b1476614a373b6700b9dd2de35c032831cdc53908ab410642e41d0dc081425620b736434ae72741e0146847564bd51b47c104446c5b7671240d65170c2925e8230e24605ecc4081bcdeb252b46b7a57179c7b6945c3e5736d98225778a708d5ea1bac58a2116e8dc90a29ec17923274d938d3d8142ed44db9b51eac0184cc7735256865d6e7e2e96be599c72838c8b3d116c90677ac18eb9574244840a1238e3cd3ae78bd9ca44daa5ca2907c5d054c204eb1eb6bba6a1c353e43829eca19a116d9d5e13910b9
* 0x7764d94281a2c84e771dac89ececb88ed93be7ed7e93d649eb8d1a5da5aec554b63bcdda79b683136269b077ec1068a27534d94038ec415829c72eb651975dee994e15d8a2b0581e011eca6cc289c3e03934b6b1933be4ec671405d50347ebd4da8e0496b11d3b0acc9a5cb159458d59ad44c2893e5b2a415c862cb46624a22557d94c9b21c0ab31de268a47daec4eaa01500c075e07cbbbe32d1c025c930545e57ac733ed9642137869cce1c4ec77ea839dce96089041475680ea5ab5a5826eab984851c44d5ac0
= 0x2e6cdd51c61380dcf2a7098984a910d5499f7c746ea684092baee4ec52fdf687e0adf94d1bd12767d52e8e38855459775cdea2cbd019876b33528d12afb439fab836febcf1d5f963368a087a1d27a75d1dd06be4e424db9ee40d433ced34c36958e20a5aac297d4ff6e93e4f734504ae2e42044836b5282e97fdca34d3c924978d73ed53c2c9a62fe6d2345ed02cfcfb98841ccacb025868ada80e12dc30ef43f97e9d45a1c9d41831942acffcd70bf7aea79246ae6072ddd8a9282e68206ab02dddf10561bce9d088fd39ff93db75fc401be4cc062e4c8e3437fed9665c20e5fedf9ab923b3d43f9ee3ac8024ddcf1b57ed15bdbb41b3d878d91e2838f2aa1b278770b93df5c31ab3cd2f17963cad9cd9ccd4271228adbba83dfd01a76002858519f31e8906ac07ebfa7ed112271d8ffe748cf041f2904b20f4bb34fbe168f070c07225204108841f718ae3f6ff938433aa480752ab6fac81cd9f5f2564131a9514229aac659d51534e73de81afa2e7efb1efe4970a3d3ff1350d0048b1fca3b06a0f74225d9611f0175317a65294c0

// Decimal equivalent.
17288807876985780382580815647772742745531674159122594230409143114791391107291113716406625278064673202018094266547209246928599224236365987006729937236407579170507073636782341401780230649190868656067814590496459400132604103355336007539268377017448796375277085780271893244383322240837000252468428299585030494956671915749270118720195476315967499530864968472088758655779737740921091656568228005198841429399211060736474404626388800171892397163103872744656956395041362720961043336145735865
* 20736496447324978532778294349856437208023202393330101487887353292223047938621589733831934293704956082745808865254103574810031063545770625761672254732098089384485702779367657549040229482708461341635573080880962579561536168141690386743615338604724311259592192581817582857178331131662853275978080906368118380027117117031685102081591279168397563487477135215783833452705889112493152738494117372061624522976590385009934606748470709134212638970263389991725083996071765076848187591118117568
= 358509303119599739390258041350418493620071359115265287562695067060576696424235394713242357804304977170388047869390878907397508405765663514213743618443338823143527289870738747387690522784591930360803520363195596557701597412383739859198408238567509317627151409784250978043337926632800705855922057477433080997997164161011018189087643475403981818580211158071021476469512126929949718303540338791417637668006087918155338044819584550549334469314014729479112724386510931301005139637392777362730577947015235812477347140055812276445561117499928314437343171694394309372475568919768366112671927881661864791452562706865273998301214801894529490379757337681058993435506813710142845233344561900611530099816532928862099029944950763489124093136827457595889685395478300070939872337879089700465833198035983916729648156331059311425974161826103241621437176515138983459227282157940745190286670874136513980107898486605617258891149423159460821568327157725994397565486729864792028944176320


And this is for computing 150!
/*

Profile results (total time)
Proc Name Self CPU Total CPU Real Time Calls
--------------------------------- --------- --------- --------- ---------
/mob/verb/FactorialTest 0.000 0.087 0.087 1
/pif_BigInt/proc/Multiply 0.051 0.085 0.085 150
/pif_BigInt/proc/SetLength 0.007 0.014 0.015 2932
/pif_BigInt/proc/_GetBlock 0.011 0.013 0.013 6995
/pif_BigInt/proc/Length 0.006 0.008 0.011 22787
/pif_BigInt/proc/_SetBlock 0.009 0.010 0.010 9709
/pif_BigInt/proc/PrintHexadecimal 0.001 0.002 0.002 1
/pif_BigInt/proc/PrintHex 0.000 0.002 0.002 1
/pif_BigInt/New 0.000 0.001 0.001 151
/pif_BigInt/proc/Set 0.001 0.001 0.001 151
/pif_BigInt/proc/BitsInteger 0.001 0.001 0.001 220
/pif_BigInt/proc/Expand 0.000 0.000 0.000 12
/pif_BigInt/proc/LargestBit 0.000 0.000 0.000 1
/pif_BigInt/proc/Sign 0.000 0.000 0.000 300
/pif_BigInt/proc/BitLength 0.000 0.000 0.000 1
/pif_BigInt/proc/SetSign 0.000 0.000 0.000 150

*/

with the output being
0x96! = 0x01d07da7ecb62cbddc2a166afb4cb7ed3175b5eb8e806e18cb2b4f4be3bbe2e3dc8207bf84713210a5db6d998a9ccff80c548cfe68ad9ca5e8e3945a223632785ec7de448c0724a0699433ff5aea1297e14dd8d12a5b851fb7c19284000000000000000000000000000000000000

// Decimal equivalent
150! = 57133839564458545904789328652610540031895535786011264182548375833179829124845398393126574488675311145377107878746854204162666250198684504466355949195922066574942592095735778929325357290444962472405416790722118445437122269675520000000000000000000000000000000000000


This is quite a significant speedup (about a 78% increase in speed). With my old method, computing 150! had a profiler output of
/*
Profile results (total time)
Proc Name Self CPU Total CPU Real Time Calls
-------------------------------------- --------- --------- --------- ---------
/mob/verb/Factorial 0.002 0.378 0.378 1
*/


I have some more ideas of how to speed it up, courtesy of Donald Knuth, but I'll have to think a little bit on how exactly that should be implemented.
In response to Nadrew
Nadrew wrote:
Now you guys just need to box that lighting stuff up into a library for the masses.

In response to Nadrew
Nadrew wrote:
Now you guys just need to box that lighting stuff up into a library for the masses.

I imagine it's a layer of objs where someone who can do much better math than me dynamically sets the icon_state to a gradient based off its neighbours, then sets to BLEND_MULTIPLY and just changes their RGB at runtime

I'd love to see it also.
In response to Bl4ck Adam
Bl4ck Adam wrote:

Panda suit!
In response to GreatPirateEra
GreatPirateEra wrote:
Nadrew wrote:
Now you guys just need to box that lighting stuff up into a library for the masses.


On an unrelated note, the occasionally-inverse correlation between code length and code efficiency is somewhat amusing, as it's unexpected. I mean, there's no hard and fast rule, but it still shows up a lot. As an example, this is the Multiplication method for this library as it currently stands.
pif_BigInt/proc

Multiply(pif_BigInt/Int)
var
// The result of multiplication.
pif_BigInt/Product = new(0)

// Current length of the product.
ProductLength = 1

// The sign of the final result.
Product_sign

// Metadata about the source object.
srcLength = src.Length()
src_sign = src.Sign() || 1 // All we need to know is whether it's non-negative, so this change a 0
// sign into a 1.

// Used for caching values. More important if src_sign = -1.
list/srcCache = new
src_carry = 1

// Metadata about the Int data.
IntLength
Int_type
Int_sign = null

Int_carry = 1

// Used for concurrent addition of new blocks for each iteration.
carry

/* Figure out what kind of data was passed. */

if(istype(Int))
IntLength = Int.Length()
Int_type = BIGINT
Int_sign = Int.Sign() || 1

else if(istext(Int))
// Not yet implemented.
Int_type = STRING

else if(args.len > 1)
IntLength = args.len
Int_type = LIST

Int = args.Copy()

else if(istype(Int, /list))
IntLength = Int:len
Int_type = LIST

Int_sign = ((Int[1] & 0x8000) == 0) ? 1 : -1

else if(isnum(Int))
IntLength = 1
Int_type = INTEGER
Int_sign = (Int < 0) ? -1 : 1

else
throw EXCEPTION("Invalid or unknown data type for processing.")

// Set the Product_sign, which we will now know (at least, we'll know whether
// it's negative or non-negative, which is enough so far).
Product_sign = Int_sign * src_sign

/* Now proceed with the multiplication algorithm. */

for(var/i = 1, i <= IntLength, i ++)
var/IntBlock

switch(Int_type)
if(BIGINT)
IntBlock = Int._GetBlock(i)
if(LIST)
IntBlock = Int[IntLength - i + 1]
if(INTEGER)
IntBlock = Int

if( (IntBlock == 0) && (i != 1) )
// If IntBlock is 0, then just skip to the next block, as nothing significant
// will occur during this iteration. We make an exception for 1, as we want to
// cache the block values for the source object.
continue

if(Int_sign == -1)
// If Int is negative, then we'll convert the block to positive and handle the
// change in sign at the end. The following uses the fact that, in two's complement
// notation, -x = ~x + 1.

IntBlock = ~IntBlock

var
IntBlock_byte1 = IntBlock & 0x00FF
IntBlock_byte2 = (IntBlock & 0xFF00) >> 8

IntBlock_byte1 = IntBlock_byte1 + Int_carry
IntBlock_byte2 = IntBlock_byte2 + ((IntBlock_byte1 & 0xFF00) >> 8)

// This will be carried to the next block when changing it from negative to positive.
// It should only be a 0 or a 1.
Int_carry = (IntBlock_byte2 & 0xFF00) >> 8

IntBlock = (IntBlock_byte1 & 0x00FF) | ((IntBlock_byte2 & 0x00FF) << 8)

// These are the nybbles of IntBlock.
var
s = (IntBlock & 0xF000) >> 12
t = (IntBlock & 0x0F00) >> 8
u = (IntBlock & 0x00F0) >> 4
v = (IntBlock & 0x000F)

// We never carry anything from one
carry = 0
for(var/j = 1, j <= srcLength, j ++)
var/srcBlock

if(i > 1)
// If we're through the first iteration, the values should have been computed and
// cached, so use them.
srcBlock = srcCache[j]
else
srcBlock = src._GetBlock(j)

if(src_sign == -1)
// If src is negative, then as above we'll convert it to positive.
srcBlock = ~srcBlock

var
srcBlock_byte1 = srcBlock & 0x00FF
srcBlock_byte2 = (srcBlock & 0xFF00) >> 8

srcBlock_byte1 = srcBlock_byte1 + src_carry
srcBlock_byte2 = srcBlock_byte2 + ((srcBlock_byte1 & 0xFF00) >> 8)

src_carry = (srcBlock_byte2 & 0xFF00) >> 8

srcBlock = (srcBlock_byte1 & 0x00FF) | ((srcBlock_byte2 & 0x00FF) << 8)

// Cache teh value.
srcCache.len ++
srcCache[j] = srcBlock

if( (j == srcLength) && (src_carry != 0) )
// If we're at the lats block, but src_carry isn't zero, then we need to
// add one more block and put src_carry at the end.
srcLength ++

srcCache.len ++
srcCache[j] = src_carry

if((srcBlock == 0) && (carry == 0))
// If srcBlock is zero and carry is zero, then nothing will happen during this
// iteration of the loop, so move onto the next one.
continue

var
// Nybbles of srcBlock.
w = (srcBlock & 0xF000) >> 12
x = (srcBlock & 0x0F00) >> 8
y = (srcBlock & 0x00F0) >> 4
z = (srcBlock & 0x000F)

// Now perform the actual multiplication. To understand the following, imagine
// writing IntBlock and srcBlock as
//
// IntBlock = (2**12)*s + (2**8)*t + (2**4)*u + v
// srcBlock = (2**12)*w + (2**8)*x + (2**4)*y + z
//
// and then factoring IntBlock*srcBlock. The following are the 'chunks' that would
// have the same power of 2 as an coefficient. This relates to their position when
// written out in binary, with each factor with a given power of 2 being bitshifted
// to the left by that power. The value in doing it this way is that we, for the
// most part, have the built-in multiplication and addition operators doing the heavy
// lifting.

// Maximum possible values.
ch0 = v*z // 0x00E1 = 0000 0000 1110 0001
ch4 = u*z + v*y // 0x01C2 = 0000 0001 1100 0010
ch8 = t*z + u*y + v*x // 0x02A3 = 0000 0010 1010 0011
ch12 = s*z + t*y + u*x + v*w // 0x0384 = 0000 0011 1000 0100
ch16 = s*y + t*x + u*w // 0x02A3 = 0000 0010 1010 0011
ch20 = s*x + t*w // 0x01C2 = 0000 0001 1100 0010
ch24 = s*w // 0x00E1 = 0000 0000 1110 0001

// Arrangement of chunks into blocks.
// (i+j+1)-th Block (i+j)-th Block (i+j-1)-th Block
// Byte 6 Byte 5 Byte 4 Byte 3 Byte 2 Byte 1
// +-----------+-----------++-----------+-----------++-----------+-----------+
// ch0 | | || | || xxxx xxxx | 1110 0001 |
// ch4 | | || | xxxx || 0001 1100 | 0010 |
// ch8 | | || | xxxx 0010 || 1010 0011 | |
// ch12 | | || xxxx | 0011 1000 || 0100 | |
// ch16 | | || xxxx 0010 | 1010 0011 || | |
// ch20 | | xxxx || 0001 1100 | 0010 || | |
// ch24 | | xxxx xxxx || 1110 0001 | || | |
// +-----------+-----------++-----------+-----------++-----------+-----------+
// Sum | 0000 0000 | 0000 0000 || 1111 1111 | 1111 1110 || 0000 0000 | 0000 0001 | (0x0000FFFE0001)
// +-----------+-----------++-----------+-----------++-----------+-----------+

// Now, we take the above and convert them into the corresponding bytes, while
// summing them into the appropriate bytes.
byte1 = (ch0 & 0x00FF) + ((ch4 & 0x000F) << 4)
byte2 = ((ch4 & 0x0FF0) >> 4) + (ch8 & 0x00FF) + ((ch12 & 0x000F) << 4)
byte3 = carry + ((ch8 & 0x0F00) >> 8) + ((ch12 & 0x0FF0) >> 4) + (ch16 & 0x00FF) + ((ch20 & 0x000F) << 4)
byte4 = ((ch12 & 0xF000) >> 12) + ((ch16 & 0xFF00) >> 8) + ((ch20 & 0x0FF0) >> 4) + (ch24 & 0xFFFF)

// Product blocks at positions (i+j)-1 and (i+j)+0 respectively.
ProductBlock_n1 = (ProductLength < (i+j-1)) ? 0x0000 : Product._GetBlock(i+j-1)
ProductBlock_0 = (ProductLength < (i+j)) ? 0x0000 : Product._GetBlock(i+j)

// Now we add the current value of the ProductBlocks to bytes one through four, in the appropriate manner
// (i.e., accounting for their binary positions)/
byte1 = byte1 + (ProductBlock_n1 & 0x00FF)
byte2 = byte2 + ((ProductBlock_n1 & 0xFF00) >> 8) + ((byte1 & 0xFF00) >> 8)
byte3 = byte3 + (ProductBlock_0 & 0x00FF) + ((byte2 & 0xFF00) >> 8)
byte4 = byte4 + ((ProductBlock_0 & 0xFF00) >> 8) + ((byte3 & 0xFF00) >> 8)

// This will be the amount carried over to the next iteration.
carry = (byte4 & 0xFF00) >> 8

// This cuts byte1, byte2, byte3, byte4 down to one byte each, so they are assuredly only
// a single byte.
byte1 = ~~(byte1 & 0x00FF)
byte2 = ~~(byte2 & 0x00FF)
byte3 = ~~(byte3 & 0x00FF)
byte4 = ~~(byte4 & 0x00FF)

// Reassign the product blocks by joinin the bytes together in the proper way.
ProductBlock_n1 = byte1 | (byte2 << 8)
ProductBlock_0 = byte3 | (byte4 << 8)

// Allocate space in the ProductBlock object as needed.

if( (ProductLength < (i+j)) && (ProductBlock_0 != 0x0000) )
Product.SetLength(i+j, 0x0000)
ProductLength = i+j

if( (ProductLength < (i+j-1)) && (ProductBlock_n1 != 0x0000) )
Product.SetLength(i+j, 0x0000)
ProductLength = i+j-1

// And store the new blocks.
if(ProductLength >= (i+j-1)) Product._SetBlock(i+j-1, ProductBlock_n1)
if(ProductLength >= (i+j)) Product._SetBlock(i+j, ProductBlock_0)

if(Product_sign == -1)
// If the Product_sign is negative, then we need to do a final pass to make sure the Product is
// actually negative.

// We set carry equal to one, as this will be where the +1 part of -x = ~x + 1 comes into play.
carry = 1
for(var/i = 1, i <= ProductLength, i ++)
var
ProductBlock = Product._GetBlock(i)

byte1 = ProductBlock & 0x00FF
byte2 = (ProductBlock & 0xFF00) >> 8

byte1 = (~byte1 & 0x00FF) + carry
byte2 = (~byte2 & 0x00FF) + ((byte1 & 0xFF00) >> 8)

carry = (byte2 & 0xFF00) >> 8

ProductBlock = (byte1 & 0x00FF) | ((byte2 & 0x00FF) << 8)
Product._SetBlock(i, ProductBlock)

// And finally, we check the most significant bit of the product. If that bit doens't match the sign
// of the product, we add a new block with the proper value.

var/LastBlock = Product._GetBlock(ProductLength)
if( (Product_sign == 1) && ((LastBlock & 0x8000) != 0)) Product.Expand(1, 0x0000)
else if((Product_sign == -1) && ((LastBlock & 0x8000) == 0)) Product.Expand(1, 0xFFFF)

// Set the sign.
Product.SetSign(Product_sign)

// And output the final result.
return Product

It's more than twice as long as the previous approach (and if I can figure out how to speed it up to be more efficient, it'll be longer still), yet it seems to be about 75% faster than the old code.
In response to Popisfizzy
I like this.
In response to Bravo1
I would probably like it to. If i understood what it was.
In response to Ghost of ET
Allows for very complicated math in order to get very precise results without Byond shitting itself in the process.
In response to Bravo1
Pft when would you ever use complicated math in programming video games xD?

















Don't answer that...
Okay, what Bravo said isn't entirely true, it's not that it allows complicated math, BYOND does that by itself, rather it allows ACCURATE math, when you do complicated math.
In response to Ghost of ET
Ghost of ET wrote:
I would probably like it to. If i understood what it was.

It's a BigInt library, and while that ("big integer") is technically correct description of it, a more-precise name would be "arbitrary precision integer arithmetic".

To be a bit clearer, BYOND has a 16-bit word length, so you can only work with integers between that fit in that word length. BYOND does some fiddly stuff with conversion to floats on the fly in the background, so it's hard to pin down exactly, but it's probably something like only being 'reliable' between -32,768 and 65,535. If BYOND had a strict int type that was 16 bits, then it would be between -32,768 and 32,768, and once you go outside that range it would roll over.

What this library does (will do, whatever) is allow you to go arbitrarily beyond that range. Once you would normally roll over, it will just allocate more space. Thus, the only effective limit is how much memory can be allocated. In principle, you would also have to worry about speed, as at a certain point you will experience slowdowns due to the expense of computing these BigInts.

In practice I don't see that being much of an issue for most people. E.g., this can compute the product of two ~400 hexadecimal digit numbers in less of a third of a second, and those numbers are on the order of 10480, so very, very massive.
In response to Popisfizzy
Mostly correct, but the number is 2.1b with 15 bits (Technically 16, but strict.)
In response to Rushnut
Rushnut wrote:
Mostly correct, but the number is 2.1b with 15 bits

I'm not sure what 2.1b is supposed to be here.

In response to Popisfizzy
You lost me at 16-bit word length.
Page: 1 2 3 ... 106 107 108 109 110 ... 349 350 351